michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * XML utility classes michael@0: */ michael@0: michael@0: #include "txXMLUtils.h" michael@0: #include "nsString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "txStringUtils.h" michael@0: #include "txNamespaceMap.h" michael@0: #include "txXPathTreeWalker.h" michael@0: #include "nsContentUtils.h" michael@0: michael@0: nsresult michael@0: txExpandedName::init(const nsAString& aQName, txNamespaceMap* aResolver, michael@0: bool aUseDefault) michael@0: { michael@0: const nsAFlatString& qName = PromiseFlatString(aQName); michael@0: const char16_t* colon; michael@0: bool valid = XMLUtils::isValidQName(qName, &colon); michael@0: if (!valid) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (colon) { michael@0: nsCOMPtr prefix = do_GetAtom(Substring(qName.get(), colon)); michael@0: int32_t namespaceID = aResolver->lookupNamespace(prefix); michael@0: if (namespaceID == kNameSpaceID_Unknown) michael@0: return NS_ERROR_FAILURE; michael@0: mNamespaceID = namespaceID; michael@0: michael@0: const char16_t *end; michael@0: qName.EndReading(end); michael@0: mLocalName = do_GetAtom(Substring(colon + 1, end)); michael@0: } michael@0: else { michael@0: mNamespaceID = aUseDefault ? aResolver->lookupNamespace(nullptr) : michael@0: kNameSpaceID_None; michael@0: mLocalName = do_GetAtom(aQName); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------/ michael@0: //- Implementation of XMLUtils -/ michael@0: //------------------------------/ michael@0: michael@0: // static michael@0: nsresult michael@0: XMLUtils::splitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix, michael@0: nsIAtom **aLocalName, int32_t* aNameSpaceID) michael@0: { michael@0: /** michael@0: * Expat can send the following: michael@0: * localName michael@0: * namespaceURIlocalName michael@0: * namespaceURIlocalNameprefix michael@0: */ michael@0: michael@0: const char16_t *uriEnd = nullptr; michael@0: const char16_t *nameEnd = nullptr; michael@0: const char16_t *pos; michael@0: for (pos = aExpatName; *pos; ++pos) { michael@0: if (*pos == kExpatSeparatorChar) { michael@0: if (uriEnd) { michael@0: nameEnd = pos; michael@0: } michael@0: else { michael@0: uriEnd = pos; michael@0: } michael@0: } michael@0: } michael@0: michael@0: const char16_t *nameStart; michael@0: if (uriEnd) { michael@0: *aNameSpaceID = michael@0: txNamespaceManager::getNamespaceID(nsDependentSubstring(aExpatName, michael@0: uriEnd)); michael@0: if (*aNameSpaceID == kNameSpaceID_Unknown) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nameStart = (uriEnd + 1); michael@0: if (nameEnd) { michael@0: const char16_t *prefixStart = nameEnd + 1; michael@0: *aPrefix = NS_NewAtom(Substring(prefixStart, pos)).take(); michael@0: if (!*aPrefix) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: else { michael@0: nameEnd = pos; michael@0: *aPrefix = nullptr; michael@0: } michael@0: } michael@0: else { michael@0: *aNameSpaceID = kNameSpaceID_None; michael@0: nameStart = aExpatName; michael@0: nameEnd = pos; michael@0: *aPrefix = nullptr; michael@0: } michael@0: michael@0: *aLocalName = NS_NewAtom(Substring(nameStart, nameEnd)).take(); michael@0: michael@0: return *aLocalName ? NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: nsresult michael@0: XMLUtils::splitQName(const nsAString& aName, nsIAtom** aPrefix, michael@0: nsIAtom** aLocalName) michael@0: { michael@0: const nsAFlatString& qName = PromiseFlatString(aName); michael@0: const char16_t* colon; michael@0: bool valid = XMLUtils::isValidQName(qName, &colon); michael@0: if (!valid) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (colon) { michael@0: const char16_t *end; michael@0: qName.EndReading(end); michael@0: michael@0: *aPrefix = NS_NewAtom(Substring(qName.get(), colon)).take(); michael@0: *aLocalName = NS_NewAtom(Substring(colon + 1, end)).take(); michael@0: } michael@0: else { michael@0: *aPrefix = nullptr; michael@0: *aLocalName = NS_NewAtom(aName).take(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * Returns true if the given string has only whitespace characters michael@0: */ michael@0: bool XMLUtils::isWhitespace(const nsAFlatString& aText) michael@0: { michael@0: nsAFlatString::const_char_iterator start, end; michael@0: aText.BeginReading(start); michael@0: aText.EndReading(end); michael@0: for ( ; start != end; ++start) { michael@0: if (!isWhitespace(*start)) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * Normalizes the value of a XML processing instruction michael@0: **/ michael@0: void XMLUtils::normalizePIValue(nsAString& piValue) michael@0: { michael@0: nsAutoString origValue(piValue); michael@0: uint32_t origLength = origValue.Length(); michael@0: uint32_t conversionLoop = 0; michael@0: char16_t prevCh = 0; michael@0: piValue.Truncate(); michael@0: michael@0: while (conversionLoop < origLength) { michael@0: char16_t ch = origValue.CharAt(conversionLoop); michael@0: switch (ch) { michael@0: case '>': michael@0: { michael@0: if (prevCh == '?') { michael@0: piValue.Append(char16_t(' ')); michael@0: } michael@0: break; michael@0: } michael@0: default: michael@0: { michael@0: break; michael@0: } michael@0: } michael@0: piValue.Append(ch); michael@0: prevCh = ch; michael@0: ++conversionLoop; michael@0: } michael@0: } michael@0: michael@0: //static michael@0: bool XMLUtils::isValidQName(const nsAFlatString& aQName, michael@0: const char16_t** aColon) michael@0: { michael@0: return NS_SUCCEEDED(nsContentUtils::CheckQName(aQName, true, aColon)); michael@0: } michael@0: michael@0: //static michael@0: bool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode) michael@0: { michael@0: nsAutoString value; michael@0: txXPathTreeWalker walker(aNode); michael@0: do { michael@0: if (walker.getAttr(nsGkAtoms::space, kNameSpaceID_XML, value)) { michael@0: if (TX_StringEqualsAtom(value, nsGkAtoms::preserve)) { michael@0: return true; michael@0: } michael@0: if (TX_StringEqualsAtom(value, nsGkAtoms::_default)) { michael@0: return false; michael@0: } michael@0: } michael@0: } while (walker.moveToParent()); michael@0: michael@0: return false; michael@0: }