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