/src/mozilla-central/security/manager/pki/nsASN1Tree.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | #include "nsASN1Tree.h" |
5 | | |
6 | | #include "mozilla/Assertions.h" |
7 | | #include "nsArrayUtils.h" |
8 | | #include "nsDebug.h" |
9 | | #include "nsIMutableArray.h" |
10 | | #include "nsString.h" |
11 | | |
12 | | NS_IMPL_ISUPPORTS(nsNSSASN1Tree, nsIASN1Tree, nsITreeView) |
13 | | |
14 | | nsNSSASN1Tree::nsNSSASN1Tree() |
15 | | : mTopNode(nullptr) |
16 | 0 | { |
17 | 0 | } |
18 | | |
19 | | nsNSSASN1Tree::~nsNSSASN1Tree() |
20 | 0 | { |
21 | 0 | ClearNodes(); |
22 | 0 | } |
23 | | |
24 | | void |
25 | | nsNSSASN1Tree::ClearNodesRecursively(myNode* n) |
26 | 0 | { |
27 | 0 | // Note: |n| is allowed to be null. |
28 | 0 |
|
29 | 0 | myNode *walk = n; |
30 | 0 | while (walk) { |
31 | 0 | myNode *kill = walk; |
32 | 0 |
|
33 | 0 | if (walk->child) { |
34 | 0 | ClearNodesRecursively(walk->child); |
35 | 0 | } |
36 | 0 |
|
37 | 0 | walk = walk->next; |
38 | 0 | delete kill; |
39 | 0 | } |
40 | 0 | } |
41 | | |
42 | | void |
43 | | nsNSSASN1Tree::ClearNodes() |
44 | 0 | { |
45 | 0 | ClearNodesRecursively(mTopNode); |
46 | 0 | mTopNode = nullptr; |
47 | 0 | } |
48 | | |
49 | | void |
50 | | nsNSSASN1Tree::InitChildsRecursively(myNode* n) |
51 | 0 | { |
52 | 0 | MOZ_ASSERT(n); |
53 | 0 | if (!n) { |
54 | 0 | return; |
55 | 0 | } |
56 | 0 | |
57 | 0 | if (!n->obj) |
58 | 0 | return; |
59 | 0 | |
60 | 0 | n->seq = do_QueryInterface(n->obj); |
61 | 0 | if (!n->seq) |
62 | 0 | return; |
63 | 0 | |
64 | 0 | // If the object is a sequence, there might still be a reason |
65 | 0 | // why it should not be displayed as a container. |
66 | 0 | // If we decide that it has all the properties to justify |
67 | 0 | // displaying as a container, we will create a new child chain. |
68 | 0 | // If we decide, it does not make sense to display as a container, |
69 | 0 | // we forget that it is a sequence by erasing n->seq. |
70 | 0 | // That way, n->seq and n->child will be either both set or both null. |
71 | 0 | |
72 | 0 | bool isContainer; |
73 | 0 | n->seq->GetIsValidContainer(&isContainer); |
74 | 0 | if (!isContainer) { |
75 | 0 | n->seq = nullptr; |
76 | 0 | return; |
77 | 0 | } |
78 | 0 | |
79 | 0 | nsCOMPtr<nsIMutableArray> asn1Objects; |
80 | 0 | n->seq->GetASN1Objects(getter_AddRefs(asn1Objects)); |
81 | 0 | uint32_t numObjects; |
82 | 0 | asn1Objects->GetLength(&numObjects); |
83 | 0 | if (!numObjects) { |
84 | 0 | n->seq = nullptr; |
85 | 0 | return; |
86 | 0 | } |
87 | 0 | |
88 | 0 | myNode *walk = nullptr; |
89 | 0 | myNode *prev = nullptr; |
90 | 0 | for (uint32_t i = 0; i < numObjects; i++) { |
91 | 0 | if (0 == i) { |
92 | 0 | n->child = walk = new myNode; |
93 | 0 | } |
94 | 0 | else { |
95 | 0 | walk = new myNode; |
96 | 0 | } |
97 | 0 |
|
98 | 0 | walk->parent = n; |
99 | 0 | if (prev) { |
100 | 0 | prev->next = walk; |
101 | 0 | } |
102 | 0 |
|
103 | 0 | walk->obj = do_QueryElementAt(asn1Objects, i); |
104 | 0 |
|
105 | 0 | InitChildsRecursively(walk); |
106 | 0 |
|
107 | 0 | prev = walk; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | void |
112 | | nsNSSASN1Tree::InitNodes() |
113 | 0 | { |
114 | 0 | ClearNodes(); |
115 | 0 |
|
116 | 0 | mTopNode = new myNode; |
117 | 0 | mTopNode->obj = mASN1Object; |
118 | 0 |
|
119 | 0 | InitChildsRecursively(mTopNode); |
120 | 0 | } |
121 | | |
122 | | NS_IMETHODIMP |
123 | | nsNSSASN1Tree::LoadASN1Structure(nsIASN1Object* asn1Object) |
124 | 0 | { |
125 | 0 | // Note: |asn1Object| is allowed to be null. |
126 | 0 |
|
127 | 0 | // The tree won't automatically re-draw if the contents |
128 | 0 | // have been changed. So I do a quick test here to let |
129 | 0 | // me know if I should forced the tree to redraw itself |
130 | 0 | // by calling RowCountChanged on it. |
131 | 0 | // |
132 | 0 | bool redraw = (mASN1Object && mTree); |
133 | 0 | int32_t rowsToDelete = 0; |
134 | 0 |
|
135 | 0 | if (redraw) { |
136 | 0 | // This is the number of rows we will be deleting after |
137 | 0 | // the contents have changed. |
138 | 0 | rowsToDelete = 0-CountVisibleNodes(mTopNode); |
139 | 0 | } |
140 | 0 |
|
141 | 0 | mASN1Object = asn1Object; |
142 | 0 | InitNodes(); |
143 | 0 |
|
144 | 0 | if (redraw) { |
145 | 0 | // The number of rows in the new content. |
146 | 0 | int32_t newRows = CountVisibleNodes(mTopNode); |
147 | 0 | mTree->BeginUpdateBatch(); |
148 | 0 | // Erase all of the old rows. |
149 | 0 | mTree->RowCountChanged(0, rowsToDelete); |
150 | 0 | // Replace them with the new contents |
151 | 0 | mTree->RowCountChanged(0, newRows); |
152 | 0 | mTree->EndUpdateBatch(); |
153 | 0 | } |
154 | 0 |
|
155 | 0 | return NS_OK; |
156 | 0 | } |
157 | | |
158 | | NS_IMETHODIMP |
159 | | nsNSSASN1Tree::GetRowCount(int32_t* aRowCount) |
160 | 0 | { |
161 | 0 | NS_ENSURE_ARG_POINTER(aRowCount); |
162 | 0 |
|
163 | 0 | if (mASN1Object) { |
164 | 0 | *aRowCount = CountVisibleNodes(mTopNode); |
165 | 0 | } else { |
166 | 0 | *aRowCount = 0; |
167 | 0 | } |
168 | 0 | return NS_OK; |
169 | 0 | } |
170 | | |
171 | | NS_IMETHODIMP |
172 | | nsNSSASN1Tree::GetSelection(nsITreeSelection** aSelection) |
173 | 0 | { |
174 | 0 | NS_ENSURE_ARG_POINTER(aSelection); |
175 | 0 | *aSelection = mSelection; |
176 | 0 | NS_IF_ADDREF(*aSelection); |
177 | 0 | return NS_OK; |
178 | 0 | } |
179 | | |
180 | | NS_IMETHODIMP |
181 | | nsNSSASN1Tree::SetSelection(nsITreeSelection* aSelection) |
182 | 0 | { |
183 | 0 | // Note: |aSelection| is allowed to be null. |
184 | 0 | mSelection = aSelection; |
185 | 0 | return NS_OK; |
186 | 0 | } |
187 | | |
188 | | NS_IMETHODIMP |
189 | | nsNSSASN1Tree::GetRowProperties(int32_t, nsAString&) |
190 | 0 | { |
191 | 0 | return NS_OK; |
192 | 0 | } |
193 | | |
194 | | NS_IMETHODIMP |
195 | | nsNSSASN1Tree::GetCellProperties(int32_t, nsTreeColumn*, nsAString&) |
196 | 0 | { |
197 | 0 | return NS_OK; |
198 | 0 | } |
199 | | |
200 | | NS_IMETHODIMP |
201 | | nsNSSASN1Tree::GetColumnProperties(nsTreeColumn*, nsAString&) |
202 | 0 | { |
203 | 0 | return NS_OK; |
204 | 0 | } |
205 | | |
206 | | NS_IMETHODIMP |
207 | | nsNSSASN1Tree::IsContainer(int32_t index, bool* _retval) |
208 | 0 | { |
209 | 0 | NS_ENSURE_ARG_MIN(index, 0); |
210 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
211 | 0 |
|
212 | 0 | myNode *n = FindNodeFromIndex(index); |
213 | 0 | if (!n) |
214 | 0 | return NS_ERROR_FAILURE; |
215 | 0 | |
216 | 0 | *_retval = (n->seq != nullptr); |
217 | 0 | return NS_OK; |
218 | 0 | } |
219 | | |
220 | | NS_IMETHODIMP |
221 | | nsNSSASN1Tree::IsContainerOpen(int32_t index, bool* _retval) |
222 | 0 | { |
223 | 0 | NS_ENSURE_ARG_MIN(index, 0); |
224 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
225 | 0 |
|
226 | 0 | myNode *n = FindNodeFromIndex(index); |
227 | 0 | if (!n || !n->seq) |
228 | 0 | return NS_ERROR_FAILURE; |
229 | 0 | |
230 | 0 | return n->seq->GetIsExpanded(_retval); |
231 | 0 | } |
232 | | |
233 | | NS_IMETHODIMP |
234 | | nsNSSASN1Tree::IsContainerEmpty(int32_t, bool* _retval) |
235 | 0 | { |
236 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
237 | 0 | *_retval = false; |
238 | 0 | return NS_OK; |
239 | 0 | } |
240 | | |
241 | | NS_IMETHODIMP |
242 | | nsNSSASN1Tree::IsSeparator(int32_t, bool* _retval) |
243 | 0 | { |
244 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
245 | 0 | *_retval = false; |
246 | 0 | return NS_OK; |
247 | 0 | } |
248 | | |
249 | | NS_IMETHODIMP |
250 | | nsNSSASN1Tree::GetLevel(int32_t index, int32_t* _retval) |
251 | 0 | { |
252 | 0 | NS_ENSURE_ARG_MIN(index, 0); |
253 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
254 | 0 |
|
255 | 0 | int32_t nodeLevel; |
256 | 0 | myNode* n = FindNodeFromIndex(index, nullptr, &nodeLevel); |
257 | 0 | if (!n) |
258 | 0 | return NS_ERROR_FAILURE; |
259 | 0 | |
260 | 0 | *_retval = nodeLevel; |
261 | 0 | return NS_OK; |
262 | 0 | } |
263 | | |
264 | | NS_IMETHODIMP |
265 | | nsNSSASN1Tree::GetImageSrc(int32_t, nsTreeColumn*, nsAString&) |
266 | 0 | { |
267 | 0 | return NS_OK; |
268 | 0 | } |
269 | | |
270 | | NS_IMETHODIMP |
271 | | nsNSSASN1Tree::GetCellValue(int32_t, nsTreeColumn*, nsAString&) |
272 | 0 | { |
273 | 0 | return NS_OK; |
274 | 0 | } |
275 | | |
276 | | NS_IMETHODIMP |
277 | | nsNSSASN1Tree::GetCellText(int32_t row, nsTreeColumn*, nsAString& _retval) |
278 | 0 | { |
279 | 0 | NS_ENSURE_ARG_MIN(row, 0); |
280 | 0 |
|
281 | 0 | _retval.Truncate(); |
282 | 0 |
|
283 | 0 | myNode* n = FindNodeFromIndex(row); |
284 | 0 | if (!n) |
285 | 0 | return NS_ERROR_FAILURE; |
286 | 0 | |
287 | 0 | // There's only one column for ASN1 dump. |
288 | 0 | return n->obj->GetDisplayName(_retval); |
289 | 0 | } |
290 | | |
291 | | NS_IMETHODIMP |
292 | | nsNSSASN1Tree::GetDisplayData(uint32_t index, nsAString& _retval) |
293 | 0 | { |
294 | 0 | myNode *n = FindNodeFromIndex(index); |
295 | 0 | if (!n) |
296 | 0 | return NS_ERROR_FAILURE; |
297 | 0 | |
298 | 0 | return n->obj->GetDisplayValue(_retval); |
299 | 0 | } |
300 | | |
301 | | NS_IMETHODIMP |
302 | | nsNSSASN1Tree::SetTree(nsITreeBoxObject* tree) |
303 | 0 | { |
304 | 0 | // Note: |tree| is allowed to be null. |
305 | 0 | mTree = tree; |
306 | 0 | return NS_OK; |
307 | 0 | } |
308 | | |
309 | | NS_IMETHODIMP |
310 | | nsNSSASN1Tree::ToggleOpenState(int32_t index) |
311 | 0 | { |
312 | 0 | NS_ENSURE_ARG_MIN(index, 0); |
313 | 0 |
|
314 | 0 | myNode *n = FindNodeFromIndex(index); |
315 | 0 | if (!n) |
316 | 0 | return NS_ERROR_FAILURE; |
317 | 0 | |
318 | 0 | if (!n->seq) |
319 | 0 | return NS_ERROR_FAILURE; |
320 | 0 | |
321 | 0 | bool IsExpanded; |
322 | 0 | n->seq->GetIsExpanded(&IsExpanded); |
323 | 0 | int32_t rowCountChange; |
324 | 0 | if (IsExpanded) { |
325 | 0 | rowCountChange = -CountVisibleNodes(n->child); |
326 | 0 | n->seq->SetIsExpanded(false); |
327 | 0 | } else { |
328 | 0 | n->seq->SetIsExpanded(true); |
329 | 0 | rowCountChange = CountVisibleNodes(n->child); |
330 | 0 | } |
331 | 0 | if (mTree) |
332 | 0 | mTree->RowCountChanged(index, rowCountChange); |
333 | 0 | return NS_OK; |
334 | 0 | } |
335 | | |
336 | | NS_IMETHODIMP |
337 | | nsNSSASN1Tree::CycleHeader(nsTreeColumn*) |
338 | 0 | { |
339 | 0 | return NS_OK; |
340 | 0 | } |
341 | | |
342 | | NS_IMETHODIMP |
343 | | nsNSSASN1Tree::SelectionChanged() |
344 | 0 | { |
345 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
346 | 0 | } |
347 | | |
348 | | NS_IMETHODIMP |
349 | | nsNSSASN1Tree::CycleCell(int32_t, nsTreeColumn*) |
350 | 0 | { |
351 | 0 | return NS_OK; |
352 | 0 | } |
353 | | |
354 | | NS_IMETHODIMP |
355 | | nsNSSASN1Tree::IsEditable(int32_t, nsTreeColumn*, bool* _retval) |
356 | 0 | { |
357 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
358 | 0 | *_retval = false; |
359 | 0 | return NS_OK; |
360 | 0 | } |
361 | | |
362 | | NS_IMETHODIMP |
363 | | nsNSSASN1Tree::IsSelectable(int32_t, nsTreeColumn*, bool* _retval) |
364 | 0 | { |
365 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
366 | 0 | *_retval = false; |
367 | 0 | return NS_OK; |
368 | 0 | } |
369 | | |
370 | | NS_IMETHODIMP |
371 | | nsNSSASN1Tree::SetCellValue(int32_t, nsTreeColumn*, const nsAString&) |
372 | 0 | { |
373 | 0 | return NS_OK; |
374 | 0 | } |
375 | | |
376 | | NS_IMETHODIMP |
377 | | nsNSSASN1Tree::SetCellText(int32_t, nsTreeColumn*, const nsAString&) |
378 | 0 | { |
379 | 0 | return NS_OK; |
380 | 0 | } |
381 | | |
382 | | NS_IMETHODIMP |
383 | | nsNSSASN1Tree::PerformAction(const char16_t*) |
384 | 0 | { |
385 | 0 | return NS_OK; |
386 | 0 | } |
387 | | |
388 | | NS_IMETHODIMP |
389 | | nsNSSASN1Tree::PerformActionOnRow(const char16_t*, int32_t) |
390 | 0 | { |
391 | 0 | return NS_OK; |
392 | 0 | } |
393 | | |
394 | | NS_IMETHODIMP |
395 | | nsNSSASN1Tree::PerformActionOnCell(const char16_t*, int32_t, nsTreeColumn*) |
396 | 0 | { |
397 | 0 | return NS_OK; |
398 | 0 | } |
399 | | |
400 | | NS_IMETHODIMP |
401 | | nsNSSASN1Tree::CanDrop(int32_t, int32_t, mozilla::dom::DataTransfer*, bool* _retval) |
402 | 0 | { |
403 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
404 | 0 | *_retval = false; |
405 | 0 | return NS_OK; |
406 | 0 | } |
407 | | |
408 | | NS_IMETHODIMP |
409 | | nsNSSASN1Tree::Drop(int32_t, int32_t, mozilla::dom::DataTransfer*) |
410 | 0 | { |
411 | 0 | return NS_OK; |
412 | 0 | } |
413 | | |
414 | | NS_IMETHODIMP |
415 | | nsNSSASN1Tree::IsSorted(bool* _retval) |
416 | 0 | { |
417 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
418 | 0 | *_retval = false; |
419 | 0 | return NS_OK; |
420 | 0 | } |
421 | | |
422 | | NS_IMETHODIMP |
423 | | nsNSSASN1Tree::GetParentIndex(int32_t rowIndex, int32_t* _retval) |
424 | 0 | { |
425 | 0 | NS_ENSURE_ARG_MIN(rowIndex, 0); |
426 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
427 | 0 |
|
428 | 0 | int32_t parentIndex = -1; |
429 | 0 |
|
430 | 0 | myNode *n = FindNodeFromIndex(rowIndex, &parentIndex); |
431 | 0 | if (!n) |
432 | 0 | return NS_ERROR_FAILURE; |
433 | 0 | |
434 | 0 | *_retval = parentIndex; |
435 | 0 | return NS_OK; |
436 | 0 | } |
437 | | |
438 | | NS_IMETHODIMP |
439 | | nsNSSASN1Tree::HasNextSibling(int32_t rowIndex, int32_t afterIndex, |
440 | | bool* _retval) |
441 | 0 | { |
442 | 0 | NS_ENSURE_ARG_MIN(rowIndex, 0); |
443 | 0 | NS_ENSURE_ARG_MIN(afterIndex, 0); |
444 | 0 | NS_ENSURE_ARG_POINTER(_retval); |
445 | 0 |
|
446 | 0 | myNode *n = FindNodeFromIndex(rowIndex); |
447 | 0 | if (!n) |
448 | 0 | return NS_ERROR_FAILURE; |
449 | 0 | |
450 | 0 | if (!n->next) { |
451 | 0 | *_retval = false; |
452 | 0 | } |
453 | 0 | else { |
454 | 0 | int32_t nTotalSize = CountVisibleNodes(n); |
455 | 0 | int32_t nLastChildPos = rowIndex + nTotalSize -1; |
456 | 0 | int32_t nextSiblingPos = nLastChildPos +1; |
457 | 0 | *_retval = (nextSiblingPos > afterIndex); |
458 | 0 | } |
459 | 0 |
|
460 | 0 | return NS_OK; |
461 | 0 | } |
462 | | |
463 | | int32_t |
464 | | nsNSSASN1Tree::CountVisibleNodes(myNode* n) |
465 | 0 | { |
466 | 0 | if (!n) |
467 | 0 | return 0; |
468 | 0 | |
469 | 0 | myNode *walk = n; |
470 | 0 | int32_t count = 0; |
471 | 0 | while (walk) { |
472 | 0 | ++count; |
473 | 0 |
|
474 | 0 | if (walk->seq) { |
475 | 0 | bool IsExpanded; |
476 | 0 | walk->seq->GetIsExpanded(&IsExpanded); |
477 | 0 | if (IsExpanded) { |
478 | 0 | count += CountVisibleNodes(walk->child); |
479 | 0 | } |
480 | 0 | } |
481 | 0 |
|
482 | 0 | walk = walk->next; |
483 | 0 | } |
484 | 0 |
|
485 | 0 | return count; |
486 | 0 | } |
487 | | |
488 | | // Entry point for find |
489 | | nsNSSASN1Tree::myNode* |
490 | | nsNSSASN1Tree::FindNodeFromIndex(int32_t wantedIndex, |
491 | | int32_t* optionalOutParentIndex, |
492 | | int32_t* optionalOutLevel) |
493 | 0 | { |
494 | 0 | MOZ_ASSERT(wantedIndex >= 0); |
495 | 0 | if (wantedIndex < 0) { |
496 | 0 | return nullptr; |
497 | 0 | } |
498 | 0 | |
499 | 0 | if (0 == wantedIndex) { |
500 | 0 | if (optionalOutLevel) { |
501 | 0 | *optionalOutLevel = 0; |
502 | 0 | } |
503 | 0 | if (optionalOutParentIndex) { |
504 | 0 | *optionalOutParentIndex = -1; |
505 | 0 | } |
506 | 0 | return mTopNode; |
507 | 0 | } |
508 | 0 |
|
509 | 0 | int32_t index = 0; |
510 | 0 | int32_t level = 0; |
511 | 0 | return FindNodeFromIndex(mTopNode, wantedIndex, index, level, |
512 | 0 | optionalOutParentIndex, optionalOutLevel); |
513 | 0 | } |
514 | | |
515 | | // Internal recursive helper function |
516 | | nsNSSASN1Tree::myNode* |
517 | | nsNSSASN1Tree::FindNodeFromIndex(myNode* n, int32_t wantedIndex, |
518 | | int32_t& indexCounter, int32_t& levelCounter, |
519 | | int32_t* optionalOutParentIndex, |
520 | | int32_t* optionalOutLevel) |
521 | 0 | { |
522 | 0 | MOZ_ASSERT(wantedIndex >= 0); |
523 | 0 | MOZ_ASSERT(indexCounter >= 0); |
524 | 0 | MOZ_ASSERT(levelCounter >= 0); |
525 | 0 | if (!n || wantedIndex < 0 || indexCounter < 0 || levelCounter < 0) { |
526 | 0 | return nullptr; |
527 | 0 | } |
528 | 0 | |
529 | 0 | myNode *walk = n; |
530 | 0 | int32_t parentIndex = indexCounter - 1; |
531 | 0 |
|
532 | 0 | while (walk) { |
533 | 0 | if (indexCounter == wantedIndex) { |
534 | 0 | if (optionalOutLevel) { |
535 | 0 | *optionalOutLevel = levelCounter; |
536 | 0 | } |
537 | 0 | if (optionalOutParentIndex) { |
538 | 0 | *optionalOutParentIndex = parentIndex; |
539 | 0 | } |
540 | 0 | return walk; |
541 | 0 | } |
542 | 0 |
|
543 | 0 | if (walk->seq) { |
544 | 0 | bool IsExpanded; |
545 | 0 | walk->seq->GetIsExpanded(&IsExpanded); |
546 | 0 | if (IsExpanded) { |
547 | 0 | ++indexCounter; // set to walk->child |
548 | 0 |
|
549 | 0 | ++levelCounter; |
550 | 0 | myNode* found = FindNodeFromIndex(walk->child, wantedIndex, indexCounter, |
551 | 0 | levelCounter, optionalOutParentIndex, |
552 | 0 | optionalOutLevel); |
553 | 0 | --levelCounter; |
554 | 0 |
|
555 | 0 | if (found) |
556 | 0 | return found; |
557 | 0 | } |
558 | 0 | } |
559 | 0 | |
560 | 0 | walk = walk->next; |
561 | 0 | if (walk) { |
562 | 0 | ++indexCounter; |
563 | 0 | } |
564 | 0 | } |
565 | 0 |
|
566 | 0 | return nullptr; |
567 | 0 | } |