46 #ifdef NPT_XML_PARSER_DEBUG
47 #define NPT_XML_Debug_0(s) NPT_Debug(s)
48 #define NPT_XML_Debug_1(s,x0) NPT_Debug(s,x0)
49 #define NPT_XML_Debug_2(s,x0,x1) NPT_Debug(s,x0,x1)
50 #define NPT_XML_Debug_3(s,x0,x1,x2) NPT_Debug(s,x0,x1,x2)
51 #define NPT_XML_Debug_4(s,x0,x1,x2,x3) NPT_Debug(s,x0,x1,x2,x3)
53 #define NPT_XML_Debug_0(s)
54 #define NPT_XML_Debug_1(s,x0)
55 #define NPT_XML_Debug_2(s,x0,x1)
56 #define NPT_XML_Debug_3(s,x0,x1,x2)
57 #define NPT_XML_Debug_4(s,x0,x1,x2,x3)
69 class NPT_XmlAttributeFinder
77 const char* namespc) :
78 m_Element(element), m_Name(name), m_Namespace(namespc) {}
81 if (attribute->m_Name == m_Name) {
84 if (m_Namespace[0] ==
'\0') {
94 const NPT_String* namespc = m_Element.GetNamespaceUri(prefix);
95 return namespc && *namespc == m_Namespace;
110 const char* m_Namespace;
116 class NPT_XmlAttributeFinderWithPrefix
119 NPT_XmlAttributeFinderWithPrefix(
const char* prefix,
const char* name) :
120 m_Prefix(prefix?prefix:
""), m_Name(name) {}
123 return attribute->m_Prefix == m_Prefix && attribute->m_Name == m_Name;
127 const char* m_Prefix;
134 class NPT_XmlTagFinder
140 NPT_XmlTagFinder(
const char* tag,
const char* namespc) :
141 m_Tag(tag), m_Namespace(namespc) {}
143 bool operator()(
const NPT_XmlNode*
const & node)
const {
145 if (element && element->
m_Tag == m_Tag) {
152 return *namespc == m_Namespace;
156 return m_Namespace[0] ==
'\0';
169 const char* m_Namespace;
175 class NPT_XmlTextFinder
178 bool operator()(
const NPT_XmlNode*
const & node)
const {
186 class NPT_XmlNamespaceCollapser
194 if (element ==
NULL)
return;
197 CollapseNamespace(element, element->
GetPrefix());
203 CollapseNamespace(element, attribute->
GetPrefix());
226 if (m_Root->m_NamespaceMap ==
NULL ||
227 (m_Root->m_NamespaceMap->GetNamespaceUri(prefix) ==
NULL && prefix !=
"xml")) {
230 if (uri) m_Root->SetNamespaceUri(prefix, uri->
GetChars());
240 const char* cursor = name;
241 while (
char c = *cursor++) {
243 unsigned int prefix_length = (
unsigned int)(cursor-name)-1;
244 m_Prefix.
Assign(name, prefix_length);
259 m_NamespaceMap(
NULL),
260 m_NamespaceParent(
NULL)
269 m_NamespaceMap(
NULL),
270 m_NamespaceParent(
NULL)
272 const char* cursor = tag;
273 while (
char c = *cursor++) {
275 unsigned int prefix_length = (
unsigned int)(cursor-tag)-1;
307 if (parent_element) {
313 namespace_parent =
NULL;
340 if (namespc ==
NULL || namespc[0] ==
'\0') {
342 }
else if (namespc[0] ==
'*' && namespc[1] ==
'\0') {
349 return item?(*item)->AsElementNode():
NULL;
375 attribute =
m_Attributes.
Find(NPT_XmlAttributeFinderWithPrefix(prefix, name));
379 (*attribute)->SetValue(value);
402 if (namespc ==
NULL || namespc[0] ==
'\0') {
404 }
else if (namespc[0] ==
'*' && namespc[1] ==
'\0') {
410 attribute =
m_Attributes.
Find(NPT_XmlAttributeFinder(*
this, name, namespc));
412 return &(*attribute)->GetValue();
435 return node?&(*node)->AsTextNode()->GetString():
NULL;
446 collapser(node_pointer);
524 if (prefix[0] ==
'x' &&
578 class NPT_XmlAccumulator {
580 NPT_XmlAccumulator();
581 ~NPT_XmlAccumulator();
583 void Append(
const char* s);
584 void AppendUTF8(
unsigned int c);
585 void Reset() { m_Valid = 0; }
586 const char* GetString();
587 NPT_Size GetSize()
const {
return m_Valid; }
588 const unsigned char* GetBuffer()
const {
return m_Buffer; }
595 unsigned char* m_Buffer;
603 NPT_XmlAccumulator::NPT_XmlAccumulator() :
613 NPT_XmlAccumulator::~NPT_XmlAccumulator()
622 NPT_XmlAccumulator::Allocate(
NPT_Size size)
625 if (m_Allocated >= size)
return;
629 m_Allocated = m_Allocated ? m_Allocated * 2 : 32;
630 }
while (m_Allocated < size);
633 unsigned char* new_buffer =
new unsigned char[m_Allocated];
636 m_Buffer = new_buffer;
643 NPT_XmlAccumulator::Append(
char c)
646 if (needed > m_Allocated) Allocate(needed);
647 m_Buffer[m_Valid++] = c;
654 NPT_XmlAccumulator::Append(
const char* s)
657 while ((c = *s++)) Append(c);
664 NPT_XmlAccumulator::AppendUTF8(
unsigned int c)
667 if (needed > m_Allocated) Allocate(needed);
671 m_Buffer[m_Valid++] = (char)c;
672 }
else if (c <= 0x7FF) {
674 m_Buffer[m_Valid++] = 0xC0|(c>>6 );
675 m_Buffer[m_Valid++] = 0x80|(c&0x3F);
676 }
else if (c <= 0xFFFF) {
678 m_Buffer[m_Valid++] = 0xE0| (c>>12 );
679 m_Buffer[m_Valid++] = 0x80|((c&0xFC0)>>6);
680 m_Buffer[m_Valid++] = 0x80| (c&0x3F );
681 }
else if (c <= 0x10FFFF) {
683 m_Buffer[m_Valid++] = 0xF0| (c>>18 );
684 m_Buffer[m_Valid++] = 0x80|((c&0x3F000)>>12);
685 m_Buffer[m_Valid++] = 0x80|((c&0xFC0 )>> 6);
686 m_Buffer[m_Valid++] = 0x80| (c&0x3F );
694 NPT_XmlAccumulator::GetString()
698 m_Buffer[m_Valid] =
'\0';
699 return (
const char*)m_Buffer;
718 if ((*item)->m_Prefix == prefix) {
720 (*item)->m_Uri = uri;
727 return m_Entries.
Add(
new Entry(prefix, uri));
738 if ((*item)->m_Prefix == prefix) {
740 return &(*item)->m_Uri;
757 if ((*item)->m_Uri == uri) {
759 return &(*item)->m_Prefix;
778 #define NPT_XML_USE_CHAR_MAP
779 #if defined(NPT_XML_USE_CHAR_MAP)
1039 #endif // defined(NPT_XML_USE_CHAR_MAP)
1044 #if defined (NPT_XML_USE_CHAR_MAP)
1045 #define NPT_XML_CHAR_IS_ANY_CHAR(c) (NPT_XmlCharMap[c] & 1)
1046 #define NPT_XML_CHAR_IS_WHITESPACE(c) (NPT_XmlCharMap[c] & 2)
1047 #define NPT_XML_CHAR_IS_NAME_CHAR(c) (NPT_XmlCharMap[c] & 4)
1048 #define NPT_XML_CHAR_IS_ENTITY_REF_CHAR(c) (NPT_XML_CHAR_IS_NAME_CHAR((c)) || ((c) == '#'))
1049 #define NPT_XML_CHAR_IS_CONTENT_CHAR(c) (NPT_XmlCharMap[c] & 8)
1050 #define NPT_XML_CHAR_IS_VALUE_CHAR(c) (NPT_XmlCharMap[c] & 16)
1052 #define NPT_XML_CHAR_IS_WHITESPACE(c) \
1053 ((c) == ' ' || (c) == '\t' || (c) == 0x0D || (c) == 0x0A)
1055 #define NPT_XML_CHAR_IS_ANY_CHAR(c) \
1056 (NPT_XML_CHAR_IS_WHITESPACE((c)) || ((c) >= 0x20))
1058 #define NPT_XML_CHAR_IS_DIGIT(c) \
1059 ((c) >= '0' && (c) <= '9')
1061 #define NPT_XML_CHAR_IS_LETTER(c) \
1062 (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || ((c) >= 0xC0 && (c) <= 0xD6) || ((c) >= 0xD8 && (c) <= 0xF6) || ((c) >= 0xF8))
1064 #define NPT_XML_CHAR_IS_NAME_CHAR(c) \
1065 (NPT_XML_CHAR_IS_DIGIT((c)) || NPT_XML_CHAR_IS_LETTER((c)) || (c) == '.' || (c) == '-' || (c) == '_' || (c) == ':')
1067 #define NPT_XML_CHAR_IS_ENTITY_REF_CHAR(c) \
1068 (NPT_XML_CHAR_IS_NAME_CHAR((c)) || ((c) == '#'))
1070 #define NPT_XML_CHAR_IS_CONTENT_CHAR(c) \
1071 (NPT_XML_CHAR_IS_ANY_CHAR((c)) && ((c) != '&') && ((c) != '<'))
1073 #define NPT_XML_CHAR_IS_VALUE_CHAR(c) \
1074 (NPT_XML_CHAR_IS_ANY_CHAR((c)) && ((c) != '&') && ((c) != '<'))
1076 #endif // defined(NPT_XML_USE_CHAR_MAP)
1096 class NPT_XmlProcessor {
1112 CONTEXT_VALUE_SINGLE_QUOTE,
1113 CONTEXT_VALUE_DOUBLE_QUOTE
1120 STATE_IN_WHITESPACE,
1122 STATE_IN_NAME_SPECIAL,
1123 STATE_IN_VALUE_START,
1126 STATE_IN_EMPTY_TAG_END,
1128 STATE_IN_PROCESSING_INSTRUCTION_START,
1129 STATE_IN_PROCESSING_INSTRUCTION,
1130 STATE_IN_PROCESSING_INSTRUCTION_END,
1132 STATE_IN_COMMENT_END_1,
1133 STATE_IN_COMMENT_END_2,
1135 STATE_IN_DTD_MARKUP_DECL,
1136 STATE_IN_DTD_MARKUP_DECL_END,
1138 STATE_IN_CDATA_END_1,
1139 STATE_IN_CDATA_END_2,
1149 NPT_XmlAccumulator m_Name;
1150 NPT_XmlAccumulator m_Value;
1151 NPT_XmlAccumulator m_Text;
1152 NPT_XmlAccumulator m_Entity;
1155 #ifdef NPT_XML_PARSER_DEBUG
1156 const char* StateName(State state) {
1158 case STATE_IN_INIT:
return "IN_INIT";
1159 case STATE_IN_BOM_EF:
return "IN_BOM_EF";
1160 case STATE_IN_BOM_BB:
return "IN_BOM_BB";
1161 case STATE_IN_WHITESPACE:
return "IN_WHITESPACE";
1162 case STATE_IN_NAME:
return "IN_NAME";
1163 case STATE_IN_NAME_SPECIAL:
return "IN_NAME_SPECIAL";
1164 case STATE_IN_VALUE_START:
return "IN_VALUE_START";
1165 case STATE_IN_VALUE:
return "IN_VALUE";
1166 case STATE_IN_TAG_START:
return "IN_TAG_START";
1167 case STATE_IN_EMPTY_TAG_END:
return "IN_EMPTY_TAG_END";
1168 case STATE_IN_CONTENT:
return "IN_CONTENT";
1169 case STATE_IN_PROCESSING_INSTRUCTION_START:
return "IN_PROCESSING_INSTRUCTION_START";
1170 case STATE_IN_PROCESSING_INSTRUCTION:
return "IN_PROCESSING_INSTRUCTION";
1171 case STATE_IN_PROCESSING_INSTRUCTION_END:
return "IN_PROCESSING_INSTRUCTION_END";
1172 case STATE_IN_COMMENT:
return "IN_COMMENT";
1173 case STATE_IN_COMMENT_END_1:
return "IN_COMMENT_END_1";
1174 case STATE_IN_COMMENT_END_2:
return "IN_COMMENT_END_2";
1175 case STATE_IN_DTD:
return "IN_DTD";
1176 case STATE_IN_DTD_MARKUP_DECL:
return "IN_DTD_MARKUP_DECL";
1177 case STATE_IN_DTD_MARKUP_DECL_END:
return "IN_DTD_MARKUP_DECL_END";
1178 case STATE_IN_CDATA:
return "IN_CDATA";
1179 case STATE_IN_CDATA_END_1:
return "IN_CDATA_END_1";
1180 case STATE_IN_CDATA_END_2:
return "IN_CDATA_END_2";
1181 case STATE_IN_SPECIAL:
return "IN_SPECIAL";
1182 case STATE_IN_ENTITY_REF:
return "IN_ENTITY_REF";
1187 const char* ContextName(Context context) {
1189 case CONTEXT_NONE:
return "NONE";
1190 case CONTEXT_OPEN_TAG:
return "OPEN_TAG";
1191 case CONTEXT_CLOSE_TAG:
return "CLOSE_TAG";
1192 case CONTEXT_ATTRIBUTE:
return "ATTRIBUTE";
1193 case CONTEXT_VALUE_SINGLE_QUOTE:
return "VALUE_SINGLE_QUOTE";
1194 case CONTEXT_VALUE_DOUBLE_QUOTE:
return "VALUE_DOUBLE_QUOTE";
1200 inline void SetState(State state) {
1204 ContextName(m_Context));
1208 inline void SetState(State state, Context context) {
1211 ContextName(m_Context),
1213 ContextName(context));
1215 m_Context = context;
1218 NPT_Result ResolveEntity(NPT_XmlAccumulator& source,
1219 NPT_XmlAccumulator& destination);
1228 m_State(STATE_IN_INIT),
1229 m_Context(CONTEXT_NONE),
1230 m_SkipNewline(false)
1238 NPT_XmlProcessor::Reset()
1240 m_State = STATE_IN_INIT;
1241 m_Context = CONTEXT_NONE;
1242 m_SkipNewline =
false;
1249 NPT_XmlProcessor::ResolveEntity(NPT_XmlAccumulator& source,
1250 NPT_XmlAccumulator& destination)
1252 const char* entity = (
const char*)source.GetString();
1255 destination.Append(
'<');
1257 destination.Append(
'>');
1259 destination.Append(
'&');
1261 destination.Append(
'"');
1263 destination.Append(
'\'');
1264 }
else if (entity[0] ==
'#') {
1267 if (entity[1] ==
'x') {
1272 while (
char c = entity[i++]) {
1274 if (c>=
'0' && c<=
'9') {
1276 }
else if (base == 16) {
1277 if (c >=
'a' && c <=
'f') {
1279 }
else if (c >=
'A' && c <=
'F') {
1285 destination.Append(source.GetString());
1288 parsed = base*parsed+digit;
1290 destination.AppendUTF8(parsed);
1293 destination.Append(source.GetString());
1303 NPT_XmlProcessor::FlushPendingText()
1305 if (m_Text.GetSize() > 0) {
1306 NPT_CHECK(m_Parser->OnCharacterData(m_Text.GetString(),
1317 NPT_XmlProcessor::ProcessBuffer(
const char* buffer,
NPT_Size size)
1321 while (size-- && (c = *buffer++)) {
1325 if (m_SkipNewline) {
1326 m_SkipNewline =
false;
1327 if (c ==
'\n')
continue;
1330 m_SkipNewline =
true;
1338 SetState(STATE_IN_WHITESPACE);
1340 }
else if (c ==
'<') {
1341 SetState(STATE_IN_TAG_START);
1343 }
else if (c == 0xEF) {
1344 SetState(STATE_IN_BOM_EF);
1349 case STATE_IN_BOM_EF:
1351 SetState(STATE_IN_BOM_BB);
1356 case STATE_IN_BOM_BB:
1358 SetState(STATE_IN_WHITESPACE);
1363 case STATE_IN_WHITESPACE:
1365 switch (m_Context) {
1368 SetState(STATE_IN_TAG_START);
1374 case CONTEXT_ATTRIBUTE:
1376 SetState(STATE_IN_EMPTY_TAG_END, CONTEXT_NONE);
1377 }
else if (c ==
'>') {
1378 SetState(STATE_IN_CONTENT, CONTEXT_NONE);
1382 SetState(STATE_IN_NAME);
1388 case CONTEXT_CLOSE_TAG:
1391 NPT_CHECK(m_Parser->OnEndElement(m_Name.GetString()));
1392 SetState(STATE_IN_CONTENT, CONTEXT_NONE);
1408 switch (m_Context) {
1409 case CONTEXT_ATTRIBUTE:
1412 SetState(STATE_IN_VALUE_START);
1418 case CONTEXT_OPEN_TAG:
1421 NPT_CHECK(m_Parser->OnStartElement(m_Name.GetString()));
1424 SetState(STATE_IN_CONTENT, CONTEXT_NONE);
1425 }
else if (c ==
'/') {
1426 SetState(STATE_IN_EMPTY_TAG_END);
1428 SetState(STATE_IN_WHITESPACE, CONTEXT_ATTRIBUTE);
1435 case CONTEXT_CLOSE_TAG:
1438 NPT_CHECK(m_Parser->OnEndElement(m_Name.GetString()));
1439 SetState(STATE_IN_CONTENT, CONTEXT_NONE);
1441 SetState(STATE_IN_WHITESPACE);
1452 case STATE_IN_NAME_SPECIAL:
1456 const unsigned char* nb = m_Name.GetBuffer();
1457 if (m_Name.GetSize() == 2) {
1461 SetState(STATE_IN_COMMENT, CONTEXT_NONE);
1464 }
else if (m_Name.GetSize() == 7) {
1473 SetState(STATE_IN_CDATA, CONTEXT_NONE);
1480 const char* special = m_Name.GetString();
1482 SetState(STATE_IN_DTD, CONTEXT_NONE);
1484 SetState(STATE_IN_SPECIAL, CONTEXT_NONE);
1492 case STATE_IN_VALUE_START:
1496 SetState(STATE_IN_VALUE, CONTEXT_VALUE_DOUBLE_QUOTE);
1497 }
else if (c ==
'\'') {
1499 SetState(STATE_IN_VALUE, CONTEXT_VALUE_SINGLE_QUOTE);
1505 case STATE_IN_VALUE:
1506 if ((c ==
'"' && m_Context == CONTEXT_VALUE_DOUBLE_QUOTE) ||
1507 (c ==
'\'' && m_Context == CONTEXT_VALUE_SINGLE_QUOTE)) {
1508 NPT_CHECK(m_Parser->OnElementAttribute(m_Name.GetString(),
1509 m_Value.GetString()));
1510 SetState(STATE_IN_WHITESPACE, CONTEXT_ATTRIBUTE);
1511 }
else if (c ==
'&') {
1513 SetState(STATE_IN_ENTITY_REF);
1515 m_Value.Append(
' ');
1523 case STATE_IN_TAG_START:
1526 SetState(STATE_IN_NAME_SPECIAL, CONTEXT_NONE);
1527 }
else if (c ==
'?') {
1528 SetState(STATE_IN_PROCESSING_INSTRUCTION, CONTEXT_NONE);
1529 }
else if (c ==
'/') {
1530 SetState(STATE_IN_NAME, CONTEXT_CLOSE_TAG);
1533 SetState(STATE_IN_NAME, CONTEXT_OPEN_TAG);
1539 case STATE_IN_EMPTY_TAG_END:
1543 SetState(STATE_IN_CONTENT, CONTEXT_NONE);
1549 case STATE_IN_ENTITY_REF:
1550 switch (m_Context) {
1551 case CONTEXT_VALUE_SINGLE_QUOTE:
1552 case CONTEXT_VALUE_DOUBLE_QUOTE:
1554 NPT_CHECK(ResolveEntity(m_Entity, m_Value));
1555 SetState(STATE_IN_VALUE);
1565 NPT_CHECK(ResolveEntity(m_Entity, m_Text));
1566 SetState(STATE_IN_CONTENT);
1579 case STATE_IN_COMMENT:
1581 SetState(STATE_IN_COMMENT_END_1);
1587 case STATE_IN_COMMENT_END_1:
1589 SetState(STATE_IN_COMMENT_END_2);
1591 SetState(STATE_IN_COMMENT);
1597 case STATE_IN_COMMENT_END_2:
1599 SetState(STATE_IN_CONTENT, CONTEXT_NONE);
1605 case STATE_IN_CONTENT:
1607 SetState(STATE_IN_TAG_START, CONTEXT_NONE);
1608 }
else if (c ==
'&') {
1610 SetState(STATE_IN_ENTITY_REF);
1616 case STATE_IN_PROCESSING_INSTRUCTION_START:
1619 case STATE_IN_PROCESSING_INSTRUCTION_END:
1621 SetState(STATE_IN_WHITESPACE, CONTEXT_NONE);
1627 case STATE_IN_PROCESSING_INSTRUCTION:
1629 SetState(STATE_IN_PROCESSING_INSTRUCTION_END);
1636 SetState(STATE_IN_DTD_MARKUP_DECL);
1637 }
else if (c ==
'>') {
1638 SetState(STATE_IN_WHITESPACE, CONTEXT_NONE);
1642 case STATE_IN_DTD_MARKUP_DECL:
1644 SetState(STATE_IN_DTD_MARKUP_DECL_END);
1648 case STATE_IN_DTD_MARKUP_DECL_END:
1650 SetState(STATE_IN_WHITESPACE, CONTEXT_NONE);
1656 case STATE_IN_CDATA:
1658 SetState(STATE_IN_CDATA_END_1);
1664 case STATE_IN_CDATA_END_1:
1666 SetState(STATE_IN_CDATA_END_2);
1670 SetState(STATE_IN_CDATA);
1674 case STATE_IN_CDATA_END_2:
1676 SetState(STATE_IN_CONTENT, CONTEXT_NONE);
1678 m_Text.Append(
"]]");
1680 SetState(STATE_IN_CDATA);
1684 case STATE_IN_SPECIAL:
1686 SetState(STATE_IN_WHITESPACE, CONTEXT_NONE);
1700 m_CurrentElement(
NULL),
1701 m_KeepWhitespace(keep_whitespace)
1720 NPT_XmlParser::Reset()
1761 NPT_Size bytes_to_read =
sizeof(buffer);
1762 if (max_bytes_to_read != 0 &&
1763 size+bytes_to_read > max_bytes_to_read) {
1764 bytes_to_read = max_bytes_to_read-size;
1766 result = stream.
Read(buffer, bytes_to_read, &bytes_read);
1772 result =
m_Processor->ProcessBuffer(buffer, bytes_read);
1778 (max_bytes_to_read == 0 || size < max_bytes_to_read));
1805 return Parse(stream, max_read, node, incremental);
1818 return Parse(xml, size, node, incremental);
1888 NPT_XML_Debug_2(
"\nNPT_XmlParser::OnElementAttribute: name=%s, value='%s'\n",
1896 if (name[0] ==
'x' &&
1901 (name[5] ==
'\0' || name[5] ==
':')) {
1917 NPT_XML_Debug_1(
"\nNPT_XmlParser::OnEndElement: %s\n", name ? name :
"NULL");
1923 const char* prefix = name;
1924 unsigned int prefix_length = 0;
1925 const char* tag = name;
1926 const char* cursor = name;
1927 while (
char c = *cursor++) {
1929 prefix_length = (
unsigned int)(cursor-name)-1;
1941 for (
unsigned int i=0; i<prefix_length; i++) {
1942 if (current_prefix[i] != prefix[i]) {
1998 class NPT_XmlAttributeWriter
2001 NPT_XmlAttributeWriter(
NPT_XmlSerializer& serializer) : m_Serializer(serializer) {}
2003 m_Serializer.Attribute(attribute->
GetPrefix(),
2016 class NPT_XmlNodeWriter
2020 m_Serializer(serializer), m_AttributeWriter(serializer) {
2021 m_Serializer.StartDocument();
2027 m_Serializer.StartElement(prefix, tag);
2035 if ((*item)->m_Prefix.IsEmpty()) {
2037 m_Serializer.Attribute(
NULL,
"xmlns", (*item)->m_Uri);
2040 m_Serializer.Attribute(
"xmlns", (*item)->m_Prefix, (*item)->m_Uri);
2047 m_Serializer.EndElement(prefix, tag);
2049 m_Serializer.Text(text->GetString());
2056 NPT_XmlAttributeWriter m_AttributeWriter;
2062 class NPT_XmlNodeCanonicalWriter
2066 struct MapChainLink {
2067 MapChainLink(MapChainLink* parent) : m_Parent(parent) {}
2068 MapChainLink* m_Parent;
2074 MapChainLink* map_chain =
NULL) :
2075 m_MapChain(map_chain),
2076 m_Serializer(serializer) {
2077 m_Serializer.StartDocument();
2083 struct SortedAttributeList {
2099 struct SortedNamespaceList {
2118 MapChainLink* m_MapChain;
2126 NPT_XmlNodeCanonicalWriter::SortedAttributeList::Add(
2131 if (namespace_uri && namespace_uri->
IsEmpty()) namespace_uri =
NULL;
2135 for (; entry; ++entry) {
2137 const NPT_String* other_namespace_uri = entry->m_NamespaceUri;
2138 if (namespace_uri &&
2139 (other_namespace_uri ==
NULL || *namespace_uri > *other_namespace_uri)) {
2142 }
else if ((namespace_uri ==
NULL && other_namespace_uri ==
NULL) ||
2143 (namespace_uri && other_namespace_uri &&
2144 *namespace_uri == *other_namespace_uri)) {
2152 Entry new_entry = {namespace_uri, attribute};
2153 m_Entries.Insert(entry, new_entry);
2160 NPT_XmlNodeCanonicalWriter::SortedAttributeList::Emit(
NPT_XmlSerializer& serializer)
2163 serializer.
Attribute(i->m_Attribute->GetPrefix(),
2164 i->m_Attribute->GetName(),
2165 i->m_Attribute->GetValue());
2173 NPT_XmlNodeCanonicalWriter::SortedNamespaceList::Add(
const NPT_String* prefix,
2178 if (prefix && !prefix->
IsEmpty()) {
2179 for (; entry; ++entry) {
2181 if (entry->m_NamespacePrefix && *prefix <= *entry->m_NamespacePrefix) {
2190 m_Entries.
Insert(entry, new_entry);
2197 NPT_XmlNodeCanonicalWriter::SortedNamespaceList::Emit(
NPT_XmlSerializer& serializer)
2200 const NPT_String* key = i->m_NamespacePrefix;
2205 serializer.
Attribute(
"xmlns", *key, *value);
2214 NPT_XmlNodeCanonicalWriter::GetNamespaceRenderedForPrefix(
const NPT_String& prefix)
const
2216 for (MapChainLink*
link = m_MapChain;
2232 NPT_XmlNodeCanonicalWriter::operator()(
NPT_XmlNode*& node)
const
2234 MapChainLink map_link(m_MapChain);
2242 const NPT_String* rendered = GetNamespaceRenderedForPrefix(prefix);
2243 if (namespace_uri && namespace_uri->
IsEmpty()) namespace_uri =
NULL;
2246 if (rendered ==
NULL) {
2248 if (namespace_uri) {
2249 map_link.m_RenderedNamespaces.Put(
"", *namespace_uri);
2254 if (namespace_uri) {
2255 compare = namespace_uri->
GetChars();
2259 if (*rendered != compare) {
2261 map_link.m_RenderedNamespaces.Put(
"", compare);
2268 if (namespace_uri && (rendered ==
NULL || *rendered != *namespace_uri)) {
2270 map_link.m_RenderedNamespaces.Put(prefix, *namespace_uri);
2275 SortedAttributeList prefixed_attributes;
2276 SortedAttributeList naked_attributes;
2280 const NPT_String& a_prefix = (*attribute)->GetPrefix();
2283 naked_attributes.Add(
NULL, *attribute);
2287 if (namespace_uri) {
2288 rendered = GetNamespaceRenderedForPrefix(a_prefix);;
2289 if (rendered ==
NULL || *rendered != *namespace_uri) {
2291 map_link.m_RenderedNamespaces.Put(a_prefix, *namespace_uri);
2293 prefixed_attributes.Add(namespace_uri, *attribute);
2299 m_Serializer.StartElement(prefix, tag);
2302 if (map_link.m_RenderedNamespaces.GetEntryCount()) {
2303 SortedNamespaceList namespaces;
2305 map_link.m_RenderedNamespaces.GetEntries().
GetFirstItem();
2308 const NPT_String& value = (*entry)->GetValue();
2309 namespaces.Add(&key, &value);
2312 namespaces.Emit(m_Serializer);
2316 naked_attributes.Emit(m_Serializer);
2317 prefixed_attributes.Emit(m_Serializer);
2320 MapChainLink* chain;
2321 if (map_link.m_RenderedNamespaces.GetEntryCount()) {
2326 element->
GetChildren().
Apply(NPT_XmlNodeCanonicalWriter(m_Serializer, chain));
2329 m_Serializer.EndElement(prefix, tag);
2331 m_Serializer.Text(text->GetString());
2340 bool shrink_empty_elements,
2341 bool add_xml_decl) :
2343 m_ElementPending(false),
2345 m_Indentation(indentation),
2346 m_ElementHasText(false),
2347 m_ShrinkEmptyElements(shrink_empty_elements),
2348 m_AddXmlDecl(add_xml_decl)
2391 *text++ = c0 >= 10 ?
'A'+(c0-10) :
'0'+c0;
2393 *text++ = c1 >= 10 ?
'A'+(c1-10) :
'0'+c1;
2415 const char* start = text;
2417 while (
char c = *text) {
2418 const char* insert =
NULL;
2433 case '&' : insert =
"&";
break;
2434 case '<' : insert =
"<";
break;
2435 case '>' :
if (!attribute) insert =
">";
break;
2436 case '"' :
if (attribute) insert =
""";
break;
2449 if (start != text) {
2468 for (
unsigned int i=0; i<needed; i+=16) {
2489 if (prefix && prefix[0]) {
2517 if (prefix && prefix[0]) {
2532 if (prefix && prefix[0]) {
2587 NPT_XmlNodeWriter node_writer(serializer);
2589 node_writer(node_pointer);
2606 NPT_XmlNodeCanonicalWriter node_writer(serializer);
2608 node_writer(node_pointer);
#define NPT_SUCCESS
Result indicating that the operation or call succeeded.
NPT_XmlProcessor * m_Processor
NPT_XmlElementNode * m_CurrentElement
virtual NPT_Result Comment(const char *comment)
virtual NPT_Result EndDocument()
static bool NPT_XmlStringIsWhitespace(const char *s, NPT_Size size)
#define NPT_XML_CHAR_IS_VALUE_CHAR(c)
virtual ~NPT_XmlSerializer()
NPT_Result Add(const T &data)
virtual NPT_Result StartDocument()
#define NPT_ERROR_INVALID_SYNTAX
NPT_XmlElementNode * m_Root
const NPT_String & GetName() const
friend class NPT_XmlTagFinder
const int NPT_ERROR_XML_TAG_MISMATCH
#define NPT_StringsEqual(s1, s2)
#define NPT_XML_Debug_1(s, x0)
void RelinkNamespaceMaps()
FileReadWriteLockPriv Entry
const NPT_String & Insert(const char *s, NPT_Ordinal where=0)
virtual NPT_XmlElementNode * AsElementNode()
const NPT_String & GetPrefix() const
QString link(const QString &path, const QString &fileName)
virtual NPT_Result Parse(const char *xml, NPT_XmlNode *&tree, bool incremental=false)
#define NPT_XML_CHAR_IS_WHITESPACE(c)
virtual NPT_Result CdataSection(const char *data)
const NPT_String & GetTag() const
NPT_Result OnElementAttribute(const char *name, const char *value)
NPT_Cardinal m_Indentation
NPT_Result SetAttribute(const char *prefix, const char *name, const char *value)
virtual NPT_Result Text(const char *text)
NPT_XmlTextNode(TokenType token_type, const char *text)
NPT_Result ProcessPending()
Iterator Find(const P &predicate, NPT_Ordinal n=0) const
NPT_Result AddChild(NPT_XmlNode *child)
NPT_OutputStream * m_Output
void SetParent(NPT_XmlNode *parent) override
NPT_List< NPT_XmlAttribute * > & GetAttributes()
NPT_Result Apply(const X &function) const
friend class NPT_XmlProcessor
#define NPT_ERROR_INVALID_STATE
const char * GetChars() const
NPT_Result OnStartElement(const char *name)
#define NPT_FAILED(result)
NPT_XmlElementNode * m_NamespaceParent
const int NPT_ERROR_XML_MULTIPLE_ROOTS
virtual NPT_Result Attribute(const char *prefix, const char *name, const char *value)
NPT_List< NPT_XmlNode * > m_Children
NPT_List< NPT_XmlAttribute * > m_Attributes
bool m_ShrinkEmptyElements
NPT_Result Serialize(NPT_XmlNode &node, NPT_OutputStream &stream, bool add_xml_decl=false)
#define NPT_ERROR_INVALID_PARAMETERS
NPT_List< NPT_XmlNode * > & GetChildren()
NPT_XmlNamespaceMap * m_NamespaceMap
void Append(const char *chars, NPT_Size size)
const NPT_String & GetValue() const
NPT_XmlParser(bool keep_whitespace=true)
NPT_Result SetNamespaceUri(const char *prefix, const char *uri)
NPT_XmlSerializer(NPT_OutputStream *output, NPT_Cardinal indentation=0, bool shrink_empty_elements=true, bool add_xml_decl=false)
friend class NPT_XmlNamespaceCollapser
#define NPT_XML_CHAR_IS_NAME_CHAR(c)
NPT_XmlNode * GetParent() const
NPT_Size GetLength() const
virtual NPT_Result StartElement(const char *prefix, const char *name)
const int NPT_ERROR_XML_INVALID_NESTING
NPT_Result MakeStandalone()
NPT_Result OnCharacterData(const char *data, NPT_Size size)
void EscapeChar(unsigned char c, char *text)
NPT_String m_IndentationPrefix
NPT_XmlElementNode * GetChild(const char *tag, const char *namespc=NPT_XML_NO_NAMESPACE, NPT_Ordinal n=0) const
NPT_Result OutputEscapedString(const char *text, bool attribute)
static const unsigned char NPT_XmlCharMap[256]
static int compare(NPT_UInt32 a, NPT_UInt32 b)
NPT_XmlElementNode * AsElementNode() override
const NPT_String * GetText(NPT_Ordinal n=0) const
#define NPT_StringLength(s)
NPT_Result AddText(const char *text)
virtual NPT_XmlTextNode * AsTextNode()
NPT_XmlElementNode(const char *tag)
virtual NPT_Result Write(const void *buffer, NPT_Size bytes_to_write, NPT_Size *bytes_written=NULL)=0
NPT_Result Serialize(NPT_XmlNode &node, NPT_OutputStream &stream, bool add_xml_decl=false)
virtual void SetParent(NPT_XmlNode *parent)
#define NPT_XML_Debug_2(s, x0, x1)
const int NPT_ERROR_XML_NO_ROOT
#define NPT_XML_Debug_3(s, x0, x1, x2)
const NPT_String * GetNamespaceUri(const char *prefix)
Iterator GetFirstItem() const
virtual NPT_Result EndElement(const char *prefix, const char *name)
const NPT_String & GetPrefix() const
const NPT_String * GetNamespaceUri(const char *prefix) const
const NPT_String * GetAttribute(const char *name, const char *namespc=NPT_XML_NO_NAMESPACE) const
#define NPT_SUCCEEDED(result)
const NPT_String * GetNamespace() const
NPT_XmlAttribute(const char *name, const char *value)
void Assign(const char *chars, NPT_Size size)
#define NPT_XML_CHAR_IS_ENTITY_REF_CHAR(c)
const NPT_String * GetNamespacePrefix(const char *uri) const
NPT_Result OnEndElement(const char *name)
virtual NPT_Result WriteString(const char *string_buffer)
NPT_Result SetNamespaceUri(const char *prefix, const char *uri)
const NPT_String * GetNamespacePrefix(const char *uri)
void SetNamespaceParent(NPT_XmlElementNode *parent)
virtual NPT_Result WriteFully(const void *buffer, NPT_Size bytes_to_write)
#define NPT_XML_CHAR_IS_ANY_CHAR(c)
NPT_Result AddAttribute(const char *name, const char *value)
void OutputIndentation(bool start)
static const NPT_String NPT_XmlNamespaceUri_Xml("http://www.w3.org/XML/1998/namespace")
#define NPT_XML_Debug_4(s, x0, x1, x2, x3)
~NPT_XmlElementNode() override
unsigned int NPT_Cardinal