diff options
Diffstat (limited to 'security/manager/pki/nsASN1Tree.cpp')
-rw-r--r-- | security/manager/pki/nsASN1Tree.cpp | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/security/manager/pki/nsASN1Tree.cpp b/security/manager/pki/nsASN1Tree.cpp new file mode 100644 index 000000000..ce9672d8d --- /dev/null +++ b/security/manager/pki/nsASN1Tree.cpp @@ -0,0 +1,573 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsASN1Tree.h" + +#include "mozilla/Assertions.h" +#include "nsArrayUtils.h" +#include "nsDebug.h" +#include "nsIMutableArray.h" +#include "nsString.h" + +NS_IMPL_ISUPPORTS(nsNSSASN1Tree, nsIASN1Tree, nsITreeView) + +nsNSSASN1Tree::nsNSSASN1Tree() + : mTopNode(nullptr) +{ +} + +nsNSSASN1Tree::~nsNSSASN1Tree() +{ + ClearNodes(); +} + +void +nsNSSASN1Tree::ClearNodesRecursively(myNode* n) +{ + // Note: |n| is allowed to be null. + + myNode *walk = n; + while (walk) { + myNode *kill = walk; + + if (walk->child) { + ClearNodesRecursively(walk->child); + } + + walk = walk->next; + delete kill; + } +} + +void +nsNSSASN1Tree::ClearNodes() +{ + ClearNodesRecursively(mTopNode); + mTopNode = nullptr; +} + +void +nsNSSASN1Tree::InitChildsRecursively(myNode* n) +{ + MOZ_ASSERT(n); + if (!n) { + return; + } + + if (!n->obj) + return; + + n->seq = do_QueryInterface(n->obj); + if (!n->seq) + return; + + // If the object is a sequence, there might still be a reason + // why it should not be displayed as a container. + // If we decide that it has all the properties to justify + // displaying as a container, we will create a new child chain. + // If we decide, it does not make sense to display as a container, + // we forget that it is a sequence by erasing n->seq. + // That way, n->seq and n->child will be either both set or both null. + + bool isContainer; + n->seq->GetIsValidContainer(&isContainer); + if (!isContainer) { + n->seq = nullptr; + return; + } + + nsCOMPtr<nsIMutableArray> asn1Objects; + n->seq->GetASN1Objects(getter_AddRefs(asn1Objects)); + uint32_t numObjects; + asn1Objects->GetLength(&numObjects); + if (!numObjects) { + n->seq = nullptr; + return; + } + + myNode *walk = nullptr; + myNode *prev = nullptr; + for (uint32_t i = 0; i < numObjects; i++) { + if (0 == i) { + n->child = walk = new myNode; + } + else { + walk = new myNode; + } + + walk->parent = n; + if (prev) { + prev->next = walk; + } + + walk->obj = do_QueryElementAt(asn1Objects, i); + + InitChildsRecursively(walk); + + prev = walk; + } +} + +void +nsNSSASN1Tree::InitNodes() +{ + ClearNodes(); + + mTopNode = new myNode; + mTopNode->obj = mASN1Object; + + InitChildsRecursively(mTopNode); +} + +NS_IMETHODIMP +nsNSSASN1Tree::LoadASN1Structure(nsIASN1Object* asn1Object) +{ + // Note: |asn1Object| is allowed to be null. + + // The tree won't automatically re-draw if the contents + // have been changed. So I do a quick test here to let + // me know if I should forced the tree to redraw itself + // by calling RowCountChanged on it. + // + bool redraw = (mASN1Object && mTree); + int32_t rowsToDelete = 0; + + if (redraw) { + // This is the number of rows we will be deleting after + // the contents have changed. + rowsToDelete = 0-CountVisibleNodes(mTopNode); + } + + mASN1Object = asn1Object; + InitNodes(); + + if (redraw) { + // The number of rows in the new content. + int32_t newRows = CountVisibleNodes(mTopNode); + mTree->BeginUpdateBatch(); + // Erase all of the old rows. + mTree->RowCountChanged(0, rowsToDelete); + // Replace them with the new contents + mTree->RowCountChanged(0, newRows); + mTree->EndUpdateBatch(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetRowCount(int32_t* aRowCount) +{ + NS_ENSURE_ARG_POINTER(aRowCount); + + if (mASN1Object) { + *aRowCount = CountVisibleNodes(mTopNode); + } else { + *aRowCount = 0; + } + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetSelection(nsITreeSelection** aSelection) +{ + NS_ENSURE_ARG_POINTER(aSelection); + *aSelection = mSelection; + NS_IF_ADDREF(*aSelection); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::SetSelection(nsITreeSelection* aSelection) +{ + // Note: |aSelection| is allowed to be null. + mSelection = aSelection; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetRowProperties(int32_t, nsAString&) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetCellProperties(int32_t, nsITreeColumn*, nsAString&) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetColumnProperties(nsITreeColumn*, nsAString&) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::IsContainer(int32_t index, bool* _retval) +{ + NS_ENSURE_ARG_MIN(index, 0); + NS_ENSURE_ARG_POINTER(_retval); + + myNode *n = FindNodeFromIndex(index); + if (!n) + return NS_ERROR_FAILURE; + + *_retval = (n->seq != nullptr); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::IsContainerOpen(int32_t index, bool* _retval) +{ + NS_ENSURE_ARG_MIN(index, 0); + NS_ENSURE_ARG_POINTER(_retval); + + myNode *n = FindNodeFromIndex(index); + if (!n || !n->seq) + return NS_ERROR_FAILURE; + + return n->seq->GetIsExpanded(_retval); +} + +NS_IMETHODIMP +nsNSSASN1Tree::IsContainerEmpty(int32_t, bool* _retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::IsSeparator(int32_t, bool* _retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetLevel(int32_t index, int32_t* _retval) +{ + NS_ENSURE_ARG_MIN(index, 0); + NS_ENSURE_ARG_POINTER(_retval); + + int32_t nodeLevel; + myNode* n = FindNodeFromIndex(index, nullptr, &nodeLevel); + if (!n) + return NS_ERROR_FAILURE; + + *_retval = nodeLevel; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetImageSrc(int32_t, nsITreeColumn*, nsAString&) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetProgressMode(int32_t, nsITreeColumn*, int32_t*) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetCellValue(int32_t, nsITreeColumn*, nsAString&) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetCellText(int32_t row, nsITreeColumn*, nsAString& _retval) +{ + NS_ENSURE_ARG_MIN(row, 0); + + _retval.Truncate(); + + myNode* n = FindNodeFromIndex(row); + if (!n) + return NS_ERROR_FAILURE; + + // There's only one column for ASN1 dump. + return n->obj->GetDisplayName(_retval); +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetDisplayData(uint32_t index, nsAString& _retval) +{ + myNode *n = FindNodeFromIndex(index); + if (!n) + return NS_ERROR_FAILURE; + + return n->obj->GetDisplayValue(_retval); +} + +NS_IMETHODIMP +nsNSSASN1Tree::SetTree(nsITreeBoxObject* tree) +{ + // Note: |tree| is allowed to be null. + mTree = tree; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::ToggleOpenState(int32_t index) +{ + NS_ENSURE_ARG_MIN(index, 0); + + myNode *n = FindNodeFromIndex(index); + if (!n) + return NS_ERROR_FAILURE; + + if (!n->seq) + return NS_ERROR_FAILURE; + + bool IsExpanded; + n->seq->GetIsExpanded(&IsExpanded); + int32_t rowCountChange; + if (IsExpanded) { + rowCountChange = -CountVisibleNodes(n->child); + n->seq->SetIsExpanded(false); + } else { + n->seq->SetIsExpanded(true); + rowCountChange = CountVisibleNodes(n->child); + } + if (mTree) + mTree->RowCountChanged(index, rowCountChange); + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::CycleHeader(nsITreeColumn*) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::SelectionChanged() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsNSSASN1Tree::CycleCell(int32_t, nsITreeColumn*) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::IsEditable(int32_t, nsITreeColumn*, bool* _retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::IsSelectable(int32_t, nsITreeColumn*, bool* _retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::SetCellValue(int32_t, nsITreeColumn*, const nsAString&) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::SetCellText(int32_t, nsITreeColumn*, const nsAString&) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::PerformAction(const char16_t*) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::PerformActionOnRow(const char16_t*, int32_t) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::PerformActionOnCell(const char16_t*, int32_t, nsITreeColumn*) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::CanDrop(int32_t, int32_t, nsIDOMDataTransfer*, bool* _retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::Drop(int32_t, int32_t, nsIDOMDataTransfer*) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::IsSorted(bool* _retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::GetParentIndex(int32_t rowIndex, int32_t* _retval) +{ + NS_ENSURE_ARG_MIN(rowIndex, 0); + NS_ENSURE_ARG_POINTER(_retval); + + int32_t parentIndex = -1; + + myNode *n = FindNodeFromIndex(rowIndex, &parentIndex); + if (!n) + return NS_ERROR_FAILURE; + + *_retval = parentIndex; + return NS_OK; +} + +NS_IMETHODIMP +nsNSSASN1Tree::HasNextSibling(int32_t rowIndex, int32_t afterIndex, + bool* _retval) +{ + NS_ENSURE_ARG_MIN(rowIndex, 0); + NS_ENSURE_ARG_MIN(afterIndex, 0); + NS_ENSURE_ARG_POINTER(_retval); + + myNode *n = FindNodeFromIndex(rowIndex); + if (!n) + return NS_ERROR_FAILURE; + + if (!n->next) { + *_retval = false; + } + else { + int32_t nTotalSize = CountVisibleNodes(n); + int32_t nLastChildPos = rowIndex + nTotalSize -1; + int32_t nextSiblingPos = nLastChildPos +1; + *_retval = (nextSiblingPos > afterIndex); + } + + return NS_OK; +} + +int32_t +nsNSSASN1Tree::CountVisibleNodes(myNode* n) +{ + if (!n) + return 0; + + myNode *walk = n; + int32_t count = 0; + while (walk) { + ++count; + + if (walk->seq) { + bool IsExpanded; + walk->seq->GetIsExpanded(&IsExpanded); + if (IsExpanded) { + count += CountVisibleNodes(walk->child); + } + } + + walk = walk->next; + } + + return count; +} + +// Entry point for find +nsNSSASN1Tree::myNode* +nsNSSASN1Tree::FindNodeFromIndex(int32_t wantedIndex, + int32_t* optionalOutParentIndex, + int32_t* optionalOutLevel) +{ + MOZ_ASSERT(wantedIndex >= 0); + if (wantedIndex < 0) { + return nullptr; + } + + if (0 == wantedIndex) { + if (optionalOutLevel) { + *optionalOutLevel = 0; + } + if (optionalOutParentIndex) { + *optionalOutParentIndex = -1; + } + return mTopNode; + } + + int32_t index = 0; + int32_t level = 0; + return FindNodeFromIndex(mTopNode, wantedIndex, index, level, + optionalOutParentIndex, optionalOutLevel); +} + +// Internal recursive helper function +nsNSSASN1Tree::myNode* +nsNSSASN1Tree::FindNodeFromIndex(myNode* n, int32_t wantedIndex, + int32_t& indexCounter, int32_t& levelCounter, + int32_t* optionalOutParentIndex, + int32_t* optionalOutLevel) +{ + MOZ_ASSERT(wantedIndex >= 0); + MOZ_ASSERT(indexCounter >= 0); + MOZ_ASSERT(levelCounter >= 0); + if (!n || wantedIndex < 0 || indexCounter < 0 || levelCounter < 0) { + return nullptr; + } + + myNode *walk = n; + int32_t parentIndex = indexCounter - 1; + + while (walk) { + if (indexCounter == wantedIndex) { + if (optionalOutLevel) { + *optionalOutLevel = levelCounter; + } + if (optionalOutParentIndex) { + *optionalOutParentIndex = parentIndex; + } + return walk; + } + + if (walk->seq) { + bool IsExpanded; + walk->seq->GetIsExpanded(&IsExpanded); + if (IsExpanded) { + ++indexCounter; // set to walk->child + + ++levelCounter; + myNode* found = FindNodeFromIndex(walk->child, wantedIndex, indexCounter, + levelCounter, optionalOutParentIndex, + optionalOutLevel); + --levelCounter; + + if (found) + return found; + } + } + + walk = walk->next; + if (walk) { + ++indexCounter; + } + } + + return nullptr; +} |