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