📄 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 <vxibuildopts.h>
#if P_VXI
#include "VXMLDocumentRep.hpp"
#include "VXMLDocument.hpp"
#include <sstream> // by CreateHiddenVariable()
#include <list> // by VXMLElementRef
#include <iostream>
#ifdef _MSC_VER
#pragma warning( disable:4512)
#pragma warning( disable:4061)
#endif
//#############################################################################
// 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());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -