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