1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is the Netscape security libraries.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Netscape Communications Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Javier Delgadillo <javi@netscape.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #include "nsASN1Tree.h"
38 : #include "nsIComponentManager.h"
39 : #include "nsString.h"
40 : #include "nsCRT.h"
41 : #include "nsIMutableArray.h"
42 : #include "nsArrayUtils.h"
43 :
44 0 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Tree, nsIASN1Tree,
45 : nsITreeView)
46 :
47 0 : nsNSSASN1Tree::nsNSSASN1Tree()
48 0 : :mTopNode(nsnull)
49 : {
50 0 : }
51 :
52 0 : nsNSSASN1Tree::~nsNSSASN1Tree()
53 : {
54 0 : ClearNodes();
55 0 : }
56 :
57 0 : void nsNSSASN1Tree::ClearNodesRecursively(myNode *n)
58 : {
59 0 : myNode *walk = n;
60 0 : while (walk) {
61 0 : myNode *kill = walk;
62 :
63 0 : if (walk->child) {
64 0 : ClearNodesRecursively(walk->child);
65 : }
66 :
67 0 : walk = walk->next;
68 0 : delete kill;
69 : }
70 0 : }
71 :
72 0 : void nsNSSASN1Tree::ClearNodes()
73 : {
74 0 : ClearNodesRecursively(mTopNode);
75 0 : mTopNode = nsnull;
76 0 : }
77 :
78 0 : void nsNSSASN1Tree::InitChildsRecursively(myNode *n)
79 : {
80 0 : if (!n->obj)
81 0 : return;
82 :
83 0 : n->seq = do_QueryInterface(n->obj);
84 0 : if (!n->seq)
85 0 : return;
86 :
87 : // If the object is a sequence, there might still be a reason
88 : // why it should not be displayed as a container.
89 : // If we decide that it has all the properties to justify
90 : // displaying as a container, we will create a new child chain.
91 : // If we decide, it does not make sense to display as a container,
92 : // we forget that it is a sequence by erasing n->seq.
93 : // That way, n->seq and n->child will be either both set or both null.
94 :
95 : bool isContainer;
96 0 : n->seq->GetIsValidContainer(&isContainer);
97 0 : if (!isContainer) {
98 0 : n->seq = nsnull;
99 0 : return;
100 : }
101 :
102 0 : nsCOMPtr<nsIMutableArray> asn1Objects;
103 0 : n->seq->GetASN1Objects(getter_AddRefs(asn1Objects));
104 : PRUint32 numObjects;
105 0 : asn1Objects->GetLength(&numObjects);
106 :
107 0 : if (!numObjects) {
108 0 : n->seq = nsnull;
109 : return;
110 : }
111 :
112 0 : myNode *walk = nsnull;
113 0 : myNode *prev = nsnull;
114 :
115 : PRUint32 i;
116 0 : nsCOMPtr<nsISupports> isupports;
117 0 : for (i=0; i<numObjects; i++) {
118 0 : if (0 == i) {
119 0 : n->child = walk = new myNode;
120 : }
121 : else {
122 0 : walk = new myNode;
123 : }
124 :
125 0 : walk->parent = n;
126 0 : if (prev) {
127 0 : prev->next = walk;
128 : }
129 :
130 0 : walk->obj = do_QueryElementAt(asn1Objects, i);
131 :
132 0 : InitChildsRecursively(walk);
133 :
134 0 : prev = walk;
135 : }
136 : }
137 :
138 0 : void nsNSSASN1Tree::InitNodes()
139 : {
140 0 : ClearNodes();
141 :
142 0 : mTopNode = new myNode;
143 0 : mTopNode->obj = mASN1Object;
144 :
145 0 : InitChildsRecursively(mTopNode);
146 0 : }
147 :
148 : /* void loadASN1Structure (in nsIASN1Object asn1Object); */
149 : NS_IMETHODIMP
150 0 : nsNSSASN1Tree::LoadASN1Structure(nsIASN1Object *asn1Object)
151 : {
152 : //
153 : // The tree won't automatically re-draw if the contents
154 : // have been changed. So I do a quick test here to let
155 : // me know if I should forced the tree to redraw itself
156 : // by calling RowCountChanged on it.
157 : //
158 0 : bool redraw = (mASN1Object && mTree);
159 0 : PRInt32 rowsToDelete = 0;
160 :
161 0 : if (redraw) {
162 : // This is the number of rows we will be deleting after
163 : // the contents have changed.
164 0 : rowsToDelete = 0-CountVisibleNodes(mTopNode);
165 : }
166 :
167 0 : mASN1Object = asn1Object;
168 0 : InitNodes();
169 :
170 0 : if (redraw) {
171 : // The number of rows in the new content.
172 0 : PRInt32 newRows = CountVisibleNodes(mTopNode);
173 0 : mTree->BeginUpdateBatch();
174 : // Erase all of the old rows.
175 0 : mTree->RowCountChanged(0, rowsToDelete);
176 : // Replace them with the new contents
177 0 : mTree->RowCountChanged(0, newRows);
178 0 : mTree->EndUpdateBatch();
179 : }
180 :
181 0 : return NS_OK;
182 : }
183 :
184 : /* readonly attribute long rowCount; */
185 : NS_IMETHODIMP
186 0 : nsNSSASN1Tree::GetRowCount(PRInt32 *aRowCount)
187 : {
188 0 : if (mASN1Object) {
189 0 : *aRowCount = CountVisibleNodes(mTopNode);
190 : } else {
191 0 : *aRowCount = 0;
192 : }
193 0 : return NS_OK;
194 : }
195 :
196 : /* attribute nsITreeSelection selection; */
197 : NS_IMETHODIMP
198 0 : nsNSSASN1Tree::GetSelection(nsITreeSelection * *aSelection)
199 : {
200 0 : *aSelection = mSelection;
201 0 : NS_IF_ADDREF(*aSelection);
202 0 : return NS_OK;
203 : }
204 :
205 : NS_IMETHODIMP
206 0 : nsNSSASN1Tree::SetSelection(nsITreeSelection * aSelection)
207 : {
208 0 : mSelection = aSelection;
209 0 : return NS_OK;
210 : }
211 :
212 : /* void getRowProperties (in long index, in nsISupportsArray properties); */
213 : NS_IMETHODIMP
214 0 : nsNSSASN1Tree::GetRowProperties(PRInt32 index, nsISupportsArray *properties)
215 : {
216 0 : return NS_OK;
217 : }
218 :
219 : /* void getCellProperties (in long row, in nsITreeColumn col,
220 : in nsISupportsArray properties); */
221 : NS_IMETHODIMP
222 0 : nsNSSASN1Tree::GetCellProperties(PRInt32 row, nsITreeColumn* col,
223 : nsISupportsArray *properties)
224 : {
225 0 : return NS_OK;
226 : }
227 :
228 : /* void getColumnProperties (in nsITreeColumn col,
229 : in nsISupportsArray properties); */
230 : NS_IMETHODIMP
231 0 : nsNSSASN1Tree::GetColumnProperties(nsITreeColumn* col,
232 : nsISupportsArray *properties)
233 : {
234 0 : return NS_OK;
235 : }
236 :
237 : /* boolean isContainer (in long index); */
238 : NS_IMETHODIMP
239 0 : nsNSSASN1Tree::IsContainer(PRInt32 index, bool *_retval)
240 : {
241 0 : myNode *n = FindNodeFromIndex(index);
242 0 : if (!n)
243 0 : return NS_ERROR_FAILURE;
244 :
245 0 : *_retval = (n->seq != nsnull);
246 0 : return NS_OK;
247 : }
248 :
249 : /* boolean isContainerOpen (in long index); */
250 : NS_IMETHODIMP
251 0 : nsNSSASN1Tree::IsContainerOpen(PRInt32 index, bool *_retval)
252 : {
253 0 : myNode *n = FindNodeFromIndex(index);
254 0 : if (!n || !n->seq)
255 0 : return NS_ERROR_FAILURE;
256 :
257 0 : n->seq->GetIsExpanded(_retval);
258 0 : return NS_OK;
259 : }
260 :
261 : /* boolean isContainerEmpty (in long index); */
262 : NS_IMETHODIMP
263 0 : nsNSSASN1Tree::IsContainerEmpty(PRInt32 index, bool *_retval)
264 : {
265 0 : *_retval = false;
266 0 : return NS_OK;
267 : }
268 :
269 : /* boolean isSeparator (in long index); */
270 : NS_IMETHODIMP
271 0 : nsNSSASN1Tree::IsSeparator(PRInt32 index, bool *_retval)
272 : {
273 0 : *_retval = false;
274 0 : return NS_OK;
275 : }
276 :
277 : /* long getLevel (in long index); */
278 : NS_IMETHODIMP
279 0 : nsNSSASN1Tree::GetLevel(PRInt32 index, PRInt32 *_retval)
280 : {
281 : PRInt32 parentIndex;
282 : PRInt32 nodeLevel;
283 :
284 0 : myNode *n = FindNodeFromIndex(index, &parentIndex, &nodeLevel);
285 0 : if (!n)
286 0 : return NS_ERROR_FAILURE;
287 :
288 0 : *_retval = nodeLevel;
289 0 : return NS_OK;
290 : }
291 :
292 : /* Astring getImageSrc (in long row, in nsITreeColumn col); */
293 : NS_IMETHODIMP
294 0 : nsNSSASN1Tree::GetImageSrc(PRInt32 row, nsITreeColumn* col,
295 : nsAString& _retval)
296 : {
297 0 : return NS_OK;
298 : }
299 :
300 : /* long getProgressMode (in long row, in nsITreeColumn col); */
301 : NS_IMETHODIMP
302 0 : nsNSSASN1Tree::GetProgressMode(PRInt32 row, nsITreeColumn* col, PRInt32* _retval)
303 : {
304 0 : return NS_OK;
305 : }
306 :
307 : /* Astring getCellValue (in long row, in nsITreeColumn col); */
308 : NS_IMETHODIMP
309 0 : nsNSSASN1Tree::GetCellValue(PRInt32 row, nsITreeColumn* col,
310 : nsAString& _retval)
311 : {
312 0 : return NS_OK;
313 : }
314 :
315 : /* Astring getCellText (in long row, in nsITreeColumn col); */
316 : NS_IMETHODIMP
317 0 : nsNSSASN1Tree::GetCellText(PRInt32 row, nsITreeColumn* col,
318 : nsAString& _retval)
319 : {
320 0 : _retval.Truncate();
321 :
322 0 : myNode* n = FindNodeFromIndex(row);
323 0 : if (!n)
324 0 : return NS_ERROR_FAILURE;
325 :
326 : // There's only one column for ASN1 dump.
327 0 : return n->obj->GetDisplayName(_retval);
328 : }
329 :
330 : /* wstring getDisplayData (in unsigned long index); */
331 : NS_IMETHODIMP
332 0 : nsNSSASN1Tree::GetDisplayData(PRUint32 index, nsAString &_retval)
333 : {
334 0 : myNode *n = FindNodeFromIndex(index);
335 0 : if (!n)
336 0 : return NS_ERROR_FAILURE;
337 :
338 0 : n->obj->GetDisplayValue(_retval);
339 0 : return NS_OK;
340 : }
341 :
342 : /* void setTree (in nsITreeBoxObject tree); */
343 : NS_IMETHODIMP
344 0 : nsNSSASN1Tree::SetTree(nsITreeBoxObject *tree)
345 : {
346 0 : mTree = tree;
347 0 : return NS_OK;
348 : }
349 :
350 : /* void toggleOpenState (in long index); */
351 : NS_IMETHODIMP
352 0 : nsNSSASN1Tree::ToggleOpenState(PRInt32 index)
353 : {
354 0 : myNode *n = FindNodeFromIndex(index);
355 0 : if (!n)
356 0 : return NS_ERROR_FAILURE;
357 :
358 0 : if (!n->seq)
359 0 : return NS_ERROR_FAILURE;
360 :
361 : bool IsExpanded;
362 0 : n->seq->GetIsExpanded(&IsExpanded);
363 : PRInt32 rowCountChange;
364 0 : if (IsExpanded) {
365 0 : rowCountChange = -CountVisibleNodes(n->child);
366 0 : n->seq->SetIsExpanded(false);
367 : } else {
368 0 : n->seq->SetIsExpanded(true);
369 0 : rowCountChange = CountVisibleNodes(n->child);
370 : }
371 0 : if (mTree)
372 0 : mTree->RowCountChanged(index, rowCountChange);
373 0 : return NS_OK;
374 : }
375 :
376 : /* void cycleHeader (in nsITreeColumn col); */
377 : NS_IMETHODIMP
378 0 : nsNSSASN1Tree::CycleHeader(nsITreeColumn* col)
379 : {
380 0 : return NS_OK;
381 : }
382 :
383 : /* void selectionChanged (); */
384 : NS_IMETHODIMP
385 0 : nsNSSASN1Tree::SelectionChanged()
386 : {
387 0 : return NS_ERROR_NOT_IMPLEMENTED;
388 : }
389 :
390 : /* void cycleCell (in long row, in nsITreeColumn col); */
391 : NS_IMETHODIMP
392 0 : nsNSSASN1Tree::CycleCell(PRInt32 row, nsITreeColumn* col)
393 : {
394 0 : return NS_OK;
395 : }
396 :
397 : /* boolean isEditable (in long row, in nsITreeColumn col); */
398 : NS_IMETHODIMP
399 0 : nsNSSASN1Tree::IsEditable(PRInt32 row, nsITreeColumn* col,
400 : bool *_retval)
401 : {
402 0 : *_retval = false;
403 0 : return NS_OK;
404 : }
405 :
406 : /* boolean isSelectable (in long row, in nsITreeColumn col); */
407 : NS_IMETHODIMP
408 0 : nsNSSASN1Tree::IsSelectable(PRInt32 row, nsITreeColumn* col,
409 : bool *_retval)
410 : {
411 0 : *_retval = false;
412 0 : return NS_OK;
413 : }
414 :
415 : /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */
416 : NS_IMETHODIMP
417 0 : nsNSSASN1Tree::SetCellValue(PRInt32 row, nsITreeColumn* col,
418 : const nsAString& value)
419 : {
420 0 : return NS_OK;
421 : }
422 :
423 : /* void setCellText (in long row, in nsITreeColumn col, in AString value); */
424 : NS_IMETHODIMP
425 0 : nsNSSASN1Tree::SetCellText(PRInt32 row, nsITreeColumn* col,
426 : const nsAString& value)
427 : {
428 0 : return NS_OK;
429 : }
430 :
431 : /* void performAction (in wstring action); */
432 : NS_IMETHODIMP
433 0 : nsNSSASN1Tree::PerformAction(const PRUnichar *action)
434 : {
435 0 : return NS_OK;
436 : }
437 :
438 : /* void performActionOnRow (in wstring action, in long row); */
439 : NS_IMETHODIMP
440 0 : nsNSSASN1Tree::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
441 : {
442 0 : return NS_OK;
443 : }
444 :
445 : /* void performActionOnCell (in wstring action, in long row, in nsITreeColumn col); */
446 : NS_IMETHODIMP
447 0 : nsNSSASN1Tree::PerformActionOnCell(const PRUnichar *action, PRInt32 row,
448 : nsITreeColumn* col)
449 : {
450 0 : return NS_OK;
451 : }
452 :
453 : //
454 : // CanDrop
455 : //
456 0 : NS_IMETHODIMP nsNSSASN1Tree::CanDrop(PRInt32 index, PRInt32 orientation,
457 : nsIDOMDataTransfer* aDataTransfer, bool *_retval)
458 : {
459 0 : NS_ENSURE_ARG_POINTER(_retval);
460 0 : *_retval = false;
461 :
462 0 : return NS_OK;
463 : }
464 :
465 :
466 : //
467 : // Drop
468 : //
469 0 : NS_IMETHODIMP nsNSSASN1Tree::Drop(PRInt32 row, PRInt32 orient, nsIDOMDataTransfer* aDataTransfer)
470 : {
471 0 : return NS_OK;
472 : }
473 :
474 :
475 : //
476 : // IsSorted
477 : //
478 : // ...
479 : //
480 0 : NS_IMETHODIMP nsNSSASN1Tree::IsSorted(bool *_retval)
481 : {
482 0 : *_retval = false;
483 0 : return NS_OK;
484 : }
485 :
486 :
487 : /* long getParentIndex (in long rowIndex); */
488 : NS_IMETHODIMP
489 0 : nsNSSASN1Tree::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval)
490 : {
491 0 : PRInt32 parentIndex = -1;
492 :
493 0 : myNode *n = FindNodeFromIndex(rowIndex, &parentIndex);
494 0 : if (!n)
495 0 : return NS_ERROR_FAILURE;
496 :
497 0 : *_retval = parentIndex;
498 0 : return NS_OK;
499 : }
500 :
501 : /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */
502 : NS_IMETHODIMP
503 0 : nsNSSASN1Tree::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex,
504 : bool *_retval)
505 : {
506 0 : myNode *n = FindNodeFromIndex(rowIndex);
507 0 : if (!n)
508 0 : return NS_ERROR_FAILURE;
509 :
510 0 : if (!n->next) {
511 0 : *_retval = false;
512 : }
513 : else {
514 0 : PRInt32 nTotalSize = CountVisibleNodes(n);
515 0 : PRInt32 nLastChildPos = rowIndex + nTotalSize -1;
516 0 : PRInt32 nextSiblingPos = nLastChildPos +1;
517 0 : *_retval = (nextSiblingPos > afterIndex);
518 : }
519 :
520 0 : return NS_OK;
521 : }
522 :
523 0 : PRInt32 nsNSSASN1Tree::CountVisibleNodes(myNode *n)
524 : {
525 0 : if (!n)
526 0 : return 0;
527 :
528 0 : myNode *walk = n;
529 0 : PRInt32 count = 0;
530 :
531 0 : while (walk) {
532 0 : ++count;
533 :
534 0 : if (walk->seq) {
535 : bool IsExpanded;
536 0 : walk->seq->GetIsExpanded(&IsExpanded);
537 0 : if (IsExpanded) {
538 0 : count += CountVisibleNodes(walk->child);
539 : }
540 : }
541 :
542 0 : walk = walk->next;
543 : }
544 :
545 0 : return count;
546 : }
547 :
548 : // Entry point for find
549 : nsNSSASN1Tree::myNode *
550 0 : nsNSSASN1Tree::FindNodeFromIndex(PRInt32 wantedIndex,
551 : PRInt32 *optionalOutParentIndex, PRInt32 *optionalOutLevel)
552 : {
553 0 : if (0 == wantedIndex) {
554 0 : if (optionalOutLevel) {
555 0 : *optionalOutLevel = 0;
556 : }
557 0 : if (optionalOutParentIndex) {
558 0 : *optionalOutParentIndex = -1;
559 : }
560 0 : return mTopNode;
561 : }
562 : else {
563 0 : PRInt32 index = 0;
564 0 : PRInt32 level = 0;
565 : return FindNodeFromIndex(mTopNode, wantedIndex, index, level,
566 0 : optionalOutParentIndex, optionalOutLevel);
567 : }
568 : }
569 :
570 : // Internal recursive helper function
571 : nsNSSASN1Tree::myNode *
572 0 : nsNSSASN1Tree::FindNodeFromIndex(myNode *n, PRInt32 wantedIndex,
573 : PRInt32 &index_counter, PRInt32 &level_counter,
574 : PRInt32 *optionalOutParentIndex, PRInt32 *optionalOutLevel)
575 : {
576 0 : if (!n)
577 0 : return nsnull;
578 :
579 0 : myNode *walk = n;
580 0 : PRInt32 parentIndex = index_counter-1;
581 :
582 0 : while (walk) {
583 0 : if (index_counter == wantedIndex) {
584 0 : if (optionalOutLevel) {
585 0 : *optionalOutLevel = level_counter;
586 : }
587 0 : if (optionalOutParentIndex) {
588 0 : *optionalOutParentIndex = parentIndex;
589 : }
590 0 : return walk;
591 : }
592 :
593 0 : if (walk->seq) {
594 : bool IsExpanded;
595 0 : walk->seq->GetIsExpanded(&IsExpanded);
596 0 : if (IsExpanded) {
597 0 : ++index_counter; // set to walk->child
598 :
599 0 : ++level_counter;
600 : myNode *found = FindNodeFromIndex(walk->child, wantedIndex, index_counter, level_counter,
601 0 : optionalOutParentIndex, optionalOutLevel);
602 0 : --level_counter;
603 :
604 0 : if (found)
605 0 : return found;
606 : }
607 : }
608 :
609 0 : walk = walk->next;
610 0 : if (walk) {
611 0 : ++index_counter;
612 : }
613 : }
614 :
615 0 : return nsnull;
616 : }
617 :
|