Coverage Report

Created: 2018-09-25 14:53

/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
}