📄 documentmodel.cpp
字号:
/****************License************************************************ * * Copyright 2000-2003. ScanSoft, Inc. * * Use of this software is subject to notices and obligations set forth * in the SpeechWorks Public License - Software Version 1.2 which is * included with this software. * * ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech, * SpeechWorks and the SpeechWorks logo are registered trademarks or * trademarks of SpeechWorks International, Inc. in the United States * and other countries. * ***********************************************************************/ #include "VXMLDocumentRep.hpp" #include "VXMLDocument.hpp" #include <sstream> // by CreateHiddenVariable() #include <list> // by VXMLElementRef #include <iostream> //############################################################################# // One mutex is shared across all the VXMLNodes. The small performance // reduction is offset by the large number of mutexes which would be otherwise // created. #include "InternalMutex.hpp" // by VXMLNodeRef static InternalMutex * mutex = NULL; bool VXMLDocumentModel::Initialize() { mutex = new InternalMutex(); return !(mutex == NULL || mutex->IsBad()); } void VXMLDocumentModel::Deinitialize() { if (mutex != NULL) delete mutex; mutex = NULL; } //############################################################################# static const VXIchar * const HIDDEN_VAR_PREFIX = L"$_internalName_"; // The cautious reader will notice that this routine is not thread safe. This // perfectly acceptible. We don't really care what the numbers are so long // as they keep incrementing. // // The 'dangerous' line is indicated with the asterisk. A context switch // would need to happen between the comparison and the assignment but only when // the threshold is exceeded. Even on those architectures which permit this // context switch, the risk is near zero. // void VXMLDocumentModel::CreateHiddenVariable(vxistring & v) { static long internalCount = 31415; // Increment counter or reset if necessary (LONG_MAX must be larger). long count = ++internalCount; if (internalCount > 2141234567) internalCount = 271828; // * std::basic_stringstream<VXIchar> name; name << HIDDEN_VAR_PREFIX << count; v = name.str(); } // As long as HIDDEN_VAR_PREFIX is sufficiently obscure, this should be good // enough. bool VXMLDocumentModel::IsHiddenVariable(const vxistring & v) { return (v.find(HIDDEN_VAR_PREFIX) == 0); } //############################################################################# // This defines the reference counted data for VXMLNodes. class VXMLNodeRef { public: const VXMLNodeRef * GetParent() const { return parent; } VXMLNode::VXMLNodeType GetType() const { return type; } virtual ~VXMLNodeRef() { } protected: VXMLNodeRef(const VXMLNodeRef * p, VXMLNode::VXMLNodeType t) : parent(p), type(t) { } const VXMLNodeRef * parent; VXMLNode::VXMLNodeType type; }; //############################################################################# // Content nodes are simple - they consist of a block of data. class VXMLContentRef : public VXMLNodeRef { public: vxistring data; VXMLContentRef(const VXMLNodeRef * p) : VXMLNodeRef(p, VXMLNode::Type_VXMLContent) { } virtual ~VXMLContentRef() { } }; //############################################################################# class VXMLElementRef : public VXMLNodeRef { public: class VXMLElementAttribute { public: VXMLAttributeType key; vxistring value; VXMLElementAttribute() { } VXMLElementAttribute(VXMLAttributeType k, const vxistring & attr) : key(k), value(attr) { } }; typedef std::list<VXMLNodeRef *> CHILDREN; typedef std::list<VXMLElementAttribute> ATTRIBUTES; VXMLElementType name; ATTRIBUTES attributes; CHILDREN children; bool GetAttribute(VXMLAttributeType key, vxistring & attr) const; VXMLElementRef(const VXMLNodeRef * p, VXMLElementType n) : VXMLNodeRef(p, VXMLNode::Type_VXMLElement), name(n) { } virtual ~VXMLElementRef() { for (CHILDREN::iterator i = children.begin(); i != children.end(); ++i) delete (*i); } }; bool VXMLElementRef::GetAttribute(VXMLAttributeType key, vxistring & attr) const { ATTRIBUTES::const_iterator i; for (i = attributes.begin(); i != attributes.end(); ++i) { if ((*i).key == key) { attr = (*i).value; return true; } } attr.erase(); return false; } //############################################################################# class VXMLNodeIteratorData { public: const VXMLElementRef & ref; VXMLElementRef::CHILDREN::const_iterator i; VXMLNodeIteratorData(const VXMLElementRef & r) : ref(r) { i = ref.children.begin(); } }; VXMLNodeIterator::VXMLNodeIterator(const VXMLNode & n) : data(NULL) { if (n.internals == NULL || n.internals->GetType() != VXMLNode::Type_VXMLElement) return; const VXMLElementRef * tmp = static_cast<const VXMLElementRef*>(n.internals); data = new VXMLNodeIteratorData(*tmp); } VXMLNodeIterator::~VXMLNodeIterator() { if (data != NULL) delete data; } void VXMLNodeIterator::operator++() { if (data != NULL) ++data->i; } void VXMLNodeIterator::reset() { if (data != NULL) data->i = data->ref.children.begin(); } VXMLNode VXMLNodeIterator::operator*() const { if (data == NULL) return VXMLNode(); return *(data->i); } VXMLNodeIterator::operator const void *() const { if (data == NULL || data->i == data->ref.children.end()) return NULL; return reinterpret_cast<void *>(1); } //############################################################################# void VXMLDocumentRep::AddRef(VXMLDocumentRep * t) { if (t == NULL) return; mutex->Lock(); ++t->count; mutex->Unlock(); } void VXMLDocumentRep::Release(VXMLDocumentRep * & t) { if (t == NULL) return; mutex->Lock(); --t->count; mutex->Unlock(); if (t->count == 0) delete t; t = NULL; } VXMLDocumentRep::VXMLDocumentRep() : root(NULL), pos(NULL), posType(VXMLNode::Type_VXMLNode), count(1) { } VXMLDocumentRep::~VXMLDocumentRep() { if (root != NULL) delete root; } void VXMLDocumentRep::AddContent(const VXIchar * c, unsigned int len) { // (0) Parameter check. if (c == NULL || len == 0) return; // (1) Handle the case where we're just appending content to an existing node if (posType == VXMLNode::Type_VXMLContent) { (static_cast<VXMLContentRef *>(pos))->data += vxistring(c, len); return; } // (2) Create new content node. VXMLContentRef * temp = new VXMLContentRef(pos); if (temp == NULL) throw VXMLDocumentModel::OutOfMemory(); temp->data = vxistring(c, len); AddChild(temp); pos = temp; posType = VXMLNode::Type_VXMLContent; } void VXMLDocumentRep::StartElement(VXMLElementType n) { if (root != NULL) { if (pos == NULL) throw VXMLDocumentModel::InternalError(); else if (posType == VXMLNode::Type_VXMLContent) { pos = const_cast<VXMLNodeRef *>(pos->GetParent()); posType = pos->GetType(); } } VXMLElementRef * temp = new VXMLElementRef(pos, n); if (temp == NULL) throw VXMLDocumentModel::OutOfMemory(); AddChild(temp); pos = temp; posType = VXMLNode::Type_VXMLElement; } void VXMLDocumentRep::PruneWhitespace() { // Set start to the current element. VXMLNodeRef * temp = pos; if (posType == VXMLNode::Type_VXMLContent) temp = const_cast<VXMLNodeRef *>(pos->GetParent()); VXMLElementRef * start = static_cast<VXMLElementRef *>(temp); for (VXMLElementRef::CHILDREN::const_iterator j = start->children.begin(); j != start->children.end(); ++j) { if ((*j)->GetType() != VXMLNode::Type_VXMLContent) continue; // Set up a very helpful reference... vxistring & str = reinterpret_cast<VXMLContentRef *>(*j)->data; vxistring::size_type len = str.length(); if (len == 0) continue; // Convert all whitespace to spaces. unsigned int i; for (i = 0; i < len; ++i) if (str[i] == '\r' || str[i] == '\n' || str[i] == '\t') str[i] = ' '; // Eliminate trailing and double spaces bool lastWasSpace = true; for (i = len; i > 0; --i) { if (str[i-1] != ' ') { lastWasSpace = false; continue; } if (lastWasSpace) str.erase(i-1, 1); else lastWasSpace = true; } // Eliminate space at very beginning. if (str[0] == ' ') str.erase(0, 1); } } void VXMLDocumentRep::EndElement() { if (pos == NULL) throw VXMLDocumentModel::InternalError(); if (posType == VXMLNode::Type_VXMLContent) { posType = pos->GetType(); pos = const_cast<VXMLNodeRef *>(pos->GetParent()); } if (pos == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -