aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2007-05-11 07:51:40 +0000
committerMike Buland <eichlan@xagasoft.com>2007-05-11 07:51:40 +0000
commit033c41ed57348abb3a418166b1fb39bfad3312de (patch)
tree72edbb0b7ff35ef35e4d533bca384b4f7c986942 /src
parentad92dc50b7cdf7cfe086f21d19442d03a90fd05d (diff)
downloadlibbu++-033c41ed57348abb3a418166b1fb39bfad3312de.tar.gz
libbu++-033c41ed57348abb3a418166b1fb39bfad3312de.tar.bz2
libbu++-033c41ed57348abb3a418166b1fb39bfad3312de.tar.xz
libbu++-033c41ed57348abb3a418166b1fb39bfad3312de.zip
Added a list template class, seems to work pretty well for now, I may have
forgotten proper cleanup in the deconstructor, but besides that you can do almost everything you need. I'll make a slist/stack next, probably with the same basic code, just a different structure (not doubley-linked). The xml system from old-libbu++ is almost completely converted, I was going to re-write it, but this seemed easier at first, it may not have been, we'll see. It almost parses everything again, and almost outputs again, and it does use streams now. The FString is partway to doing minimum chunk allocations, so that adding single-characters will be really fast up to the minimum chunk size. I also figured out how to add this optimization without any extra variables taking up space, and it's optional in the template, which is cool. You can specify the size of the blocks (default 256 bytes), if it's 0 then they'll be like the old FString, 1 chunk per operation. The next FString update should be allowing efficient removal from the begining of the string by faking it, and simply moving a secondary base pointer ahead, and then optimizing appends after that fact to simply move the existing data around if you shouldn't have to re-allocate (alla FlexBuf). The final fun addition that I'm planning is a simple switch in the template (boolean) that will switch an FString into a thread-safe mode without changing the interface or anything that you can do with them at all. It may increasing memory usage, but they should still be better than std::strings, and totally thread-safe. The best part of that is that if it's done with a boolean template parameter and if statements that only test that parameter controlling flow, the code that you don't want (threadsafe/non-threadsafe) won't be included at all post-optimization.
Diffstat (limited to '')
-rw-r--r--src/fstring.h14
-rw-r--r--src/list.cpp2
-rw-r--r--src/list.h176
-rw-r--r--src/tests/list.cpp22
-rw-r--r--src/tests/xml.cpp6
-rw-r--r--src/xmldocument.cpp20
-rw-r--r--src/xmldocument.h8
-rw-r--r--src/xmlnode.cpp106
-rw-r--r--src/xmlnode.h101
-rw-r--r--src/xmlreader.cpp170
-rw-r--r--src/xmlreader.h31
-rw-r--r--src/xmlwriter.cpp62
-rw-r--r--src/xmlwriter.h16
13 files changed, 428 insertions, 306 deletions
diff --git a/src/fstring.h b/src/fstring.h
index 877e5a7..f738f63 100644
--- a/src/fstring.h
+++ b/src/fstring.h
@@ -28,7 +28,7 @@ namespace Bu
28 * data is actually copied. This also means that you never need to put any 28 * data is actually copied. This also means that you never need to put any
29 * FBasicString into a ref-counting container class. 29 * FBasicString into a ref-counting container class.
30 */ 30 */
31 template< typename chr, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > 31 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
32 class FBasicString : public Archival 32 class FBasicString : public Archival
33 { 33 {
34#ifndef VALTEST 34#ifndef VALTEST
@@ -36,7 +36,7 @@ namespace Bu
36#endif 36#endif
37 private: 37 private:
38 typedef struct FStringChunk<chr> Chunk; 38 typedef struct FStringChunk<chr> Chunk;
39 typedef struct FBasicString<chr, chralloc, chunkalloc> MyType; 39 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
40 40
41 public: 41 public:
42 FBasicString() : 42 FBasicString() :
@@ -131,6 +131,11 @@ namespace Bu
131 appendChunk( pNew ); 131 appendChunk( pNew );
132 } 132 }
133 133
134 void append( const chr cData )
135 {
136 append( &cData, 1 );
137 }
138
134 void prepend( const chr *pData ) 139 void prepend( const chr *pData )
135 { 140 {
136 long nLen; 141 long nLen;
@@ -231,8 +236,7 @@ namespace Bu
231 236
232 MyType &operator +=( const chr pData ) 237 MyType &operator +=( const chr pData )
233 { 238 {
234 chr tmp[2] = { pData, (chr)0 }; 239 append( &pData, 1 );
235 append( tmp );
236 240
237 return (*this); 241 return (*this);
238 } 242 }
@@ -475,7 +479,7 @@ namespace Bu
475 } 479 }
476 } 480 }
477 481
478 void copyFrom( const FBasicString<chr, chralloc, chunkalloc> &rSrc ) 482 void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc )
479 { 483 {
480 if( rSrc.pFirst == NULL ) 484 if( rSrc.pFirst == NULL )
481 return; 485 return;
diff --git a/src/list.cpp b/src/list.cpp
new file mode 100644
index 0000000..abe92ad
--- /dev/null
+++ b/src/list.cpp
@@ -0,0 +1,2 @@
1#include "bu/list.h"
2
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..ec63496
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,176 @@
1#ifndef LIST_H
2#define LIST_H
3
4#include <memory>
5#include "bu/exceptionbase.h"
6
7namespace Bu
8{
9 template<typename value>
10 struct ListLink
11 {
12 value *pValue;
13 ListLink *pNext;
14 ListLink *pPrev;
15 };
16 template<typename value, typename valuealloc=std::allocator<value>, typename linkalloc=std::allocator<struct ListLink<value> > >
17 class List
18 {
19 private:
20 typedef struct ListLink<value> Link;
21 typedef class List<value, valuealloc, linkalloc> MyType;
22
23 public:
24 List() :
25 pFirst( NULL ),
26 pLast( NULL )
27 {
28 }
29
30 void append( value v )
31 {
32 Link *pNew = la.allocate( sizeof( Link ) );
33 pNew->pValue = va.allocate( sizeof( value ) );
34 va.construct( pNew->pValue, v );
35 if( pFirst == NULL )
36 {
37 // Empty list
38 pFirst = pLast = pNew;
39 pNew->pNext = pNew->pPrev = NULL;
40 }
41 else
42 {
43 pNew->pNext = NULL;
44 pNew->pPrev = pLast;
45 pLast->pNext = pNew;
46 pLast = pNew;
47 }
48 }
49
50 void prepend( value v )
51 {
52 Link *pNew = la.allocate( sizeof( Link ) );
53 pNew->pValue = va.allocate( sizeof( value ) );
54 va.construct( pNew->pValue, v );
55 if( pFirst == NULL )
56 {
57 // Empty list
58 pFirst = pLast = pNew;
59 pNew->pNext = pNew->pPrev = NULL;
60 }
61 else
62 {
63 pNew->pNext = pFirst;
64 pNew->pPrev = NULL;
65 pFirst->pPrev = pNew;
66 pFirst = pNew;
67 }
68 }
69
70 typedef struct iterator
71 {
72 friend class List<value, valuealloc, linkalloc>;
73 private:
74 Link *pLink;
75 iterator() :
76 pLink( NULL )
77 {
78 }
79
80 iterator( Link *pLink ) :
81 pLink( pLink )
82 {
83 }
84
85 public:
86 bool operator==( const iterator &oth )
87 {
88 return ( pLink == oth.pLink );
89 }
90
91 bool operator==( const Link *pOth )
92 {
93 return ( pLink == pOth );
94 }
95
96 bool operator!=( const iterator &oth )
97 {
98 return ( pLink != oth.pLink );
99 }
100
101 bool operator!=( const Link *pOth )
102 {
103 return ( pLink != pOth );
104 }
105
106 value &operator*()
107 {
108 return *(pLink->pValue);
109 }
110
111 value *operator->()
112 {
113 return pLink->pValue();
114 }
115
116 iterator operator++()
117 {
118 if( pLink != NULL )
119 pLink = pLink->pNext;
120 return *this;
121 }
122
123 iterator operator--()
124 {
125 if( pLink != NULL )
126 pLink = pLink->pPrev;
127 return *this;
128 }
129
130 iterator operator++( int )
131 {
132 if( pLink != NULL )
133 pLink = pLink->pNext;
134 return *this;
135 }
136
137 iterator operator--( int )
138 {
139 if( pLink != NULL )
140 pLink = pLink->pPrev;
141 return *this;
142 }
143
144 iterator operator=( const iterator &oth )
145 {
146 pLink = oth.pLink;
147 }
148 };
149
150 iterator begin()
151 {
152 return iterator( pFirst );
153 }
154
155 const Link *end()
156 {
157 return NULL;
158 }
159
160 int getSize()
161 {
162 int j = 0;
163 for( Link *pCur = pFirst; pCur; pCur = pCur->pNext )
164 j++;
165 return j;
166 }
167
168 private:
169 Link *pFirst;
170 Link *pLast;
171 linkalloc la;
172 valuealloc va;
173 };
174}
175
176#endif
diff --git a/src/tests/list.cpp b/src/tests/list.cpp
new file mode 100644
index 0000000..34ab656
--- /dev/null
+++ b/src/tests/list.cpp
@@ -0,0 +1,22 @@
1#include "bu/list.h"
2
3int main()
4{
5 Bu::List<int> l;
6
7 l.append( 0 );
8
9 for( int j = 3; j <= 21; j += 3 )
10 {
11 l.append( j );
12 l.prepend( -j );
13 }
14
15 for( Bu::List<int>::iterator i = l.begin(); i != l.end(); i++ )
16 {
17 printf("%d ", *i );
18 }
19
20 printf("\n\n");
21}
22
diff --git a/src/tests/xml.cpp b/src/tests/xml.cpp
index 9ef6a7e..9689a28 100644
--- a/src/tests/xml.cpp
+++ b/src/tests/xml.cpp
@@ -6,9 +6,9 @@
6int main() 6int main()
7{ 7{
8 Bu::File f("test.xml", "r"); 8 Bu::File f("test.xml", "r");
9 Bu::XmlReader xr( f ); 9 XmlReader xr( f );
10 10
11 xr.read(); 11 //xr.read();
12 12
13 return 0; 13 return 0;
14} 14}
diff --git a/src/xmldocument.cpp b/src/xmldocument.cpp
index d7867d5..95b9788 100644
--- a/src/xmldocument.cpp
+++ b/src/xmldocument.cpp
@@ -1,6 +1,6 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include "xmlwriter.h" 3#include "xmldocument.h"
4 4
5XmlDocument::XmlDocument( XmlNode *pRoot ) 5XmlDocument::XmlDocument( XmlNode *pRoot )
6{ 6{
@@ -17,28 +17,23 @@ XmlDocument::~XmlDocument()
17 } 17 }
18} 18}
19 19
20void XmlDocument::addNode( const char *sName, const char *sContent, bool bClose ) 20void XmlDocument::addNode( const Bu::FString &sName )
21{ 21{
22 if( pRoot == NULL ) 22 if( pRoot == NULL )
23 { 23 {
24 // This is the first node, so ignore position and just insert it. 24 // This is the first node, so ignore position and just insert it.
25 pCurrent = pRoot = new XmlNode( sName, NULL, sContent ); 25 pCurrent = pRoot = new XmlNode( sName );
26 } 26 }
27 else 27 else
28 { 28 {
29 pCurrent = pCurrent->addChild( sName, sContent ); 29 pCurrent = pCurrent->addChild( sName );
30 }
31
32 if( bClose )
33 {
34 closeNode();
35 } 30 }
36} 31}
37 32/*
38void XmlDocument::setName( const char *sName ) 33void XmlDocument::setName( const char *sName )
39{ 34{
40 pCurrent->setName( sName ); 35 pCurrent->setName( sName );
41} 36}*/
42 37
43bool XmlDocument::isCompleted() 38bool XmlDocument::isCompleted()
44{ 39{
@@ -143,7 +138,8 @@ void XmlDocument::setContent( const char *sContent )
143{ 138{
144 if( pCurrent ) 139 if( pCurrent )
145 { 140 {
146 pCurrent->setContent( sContent ); 141 printf("XmlDocument::setContent: not yet implemented.\n");
142 //pCurrent->setContent( sContent );
147 } 143 }
148} 144}
149 145
diff --git a/src/xmldocument.h b/src/xmldocument.h
index 6671c41..e0c36eb 100644
--- a/src/xmldocument.h
+++ b/src/xmldocument.h
@@ -39,13 +39,7 @@ public:
39 * the node and setting the content and name. If this is set to true the 39 * the node and setting the content and name. If this is set to true the
40 * node is appended, but the context node doesn't change. 40 * node is appended, but the context node doesn't change.
41 */ 41 */
42 void addNode( const char *sName=NULL, const char *sContent=NULL, bool bClose=false ); 42 void addNode( const Bu::FString &sName );
43
44 /**
45 * Set the name of the current node context.
46 *@param sName The new name of the node.
47 */
48 void setName( const char *sName );
49 43
50 /** 44 /**
51 * Close the current node context. This will move the current context to 45 * Close the current node context. This will move the current context to
diff --git a/src/xmlnode.cpp b/src/xmlnode.cpp
index b1ed9a9..96d5850 100644
--- a/src/xmlnode.cpp
+++ b/src/xmlnode.cpp
@@ -1,53 +1,15 @@
1#include "xmlnode.h" 1#include "xmlnode.h"
2#include "hashfunctionstring.h"
3 2
4XmlNode::XmlNode( const char *sName, XmlNode *pParent, const char *sContent ) : 3XmlNode::XmlNode( const Bu::FString &sName, XmlNode *pParent ) :
5 hProperties( new HashFunctionString(), 53, false ), 4 sName( sName ),
6 hChildren( new HashFunctionString(), 53, true ) 5 pParent( pParent )
7{ 6{
8 this->pParent = pParent;
9 if( sName != NULL )
10 {
11 setName( sName );
12 }
13 if( sContent != NULL )
14 {
15 this->sPreContent = new std::string( sContent );
16 }
17 else
18 {
19 this->sPreContent = NULL;
20 }
21 nCurContent = 0;
22} 7}
23 8
24XmlNode::~XmlNode() 9XmlNode::~XmlNode()
25{ 10{
26 for( int j = 0; j < lChildren.getSize(); j++ )
27 {
28 delete (XmlNode *)lChildren[j];
29 }
30 for( int j = 0; j < lPropNames.getSize(); j++ )
31 {
32 delete (std::string *)lPropNames[j];
33 }
34 for( int j = 0; j < lPropValues.getSize(); j++ )
35 {
36 delete (std::string *)lPropValues[j];
37 }
38 for( int j = 0; j < lPostContent.getSize(); j++ )
39 {
40 if( lPostContent[j] != NULL )
41 {
42 delete (std::string *)lPostContent[j];
43 }
44 }
45 if( sPreContent )
46 {
47 delete sPreContent;
48 }
49} 11}
50 12/*
51void XmlNode::setName( const char *sName ) 13void XmlNode::setName( const char *sName )
52{ 14{
53 if( pParent ) 15 if( pParent )
@@ -120,18 +82,18 @@ const char *XmlNode::getContent( int nIndex )
120 } 82 }
121 83
122 return NULL; 84 return NULL;
123} 85}*/
124 86
125XmlNode *XmlNode::addChild( const char *sName, const char *sContent ) 87XmlNode *XmlNode::addChild( const Bu::FString &sName )
126{ 88{
127 return addChild( new XmlNode( sName, this, sContent ) ); 89 return addChild( new XmlNode( sName, this ) );
128} 90}
129 91
130XmlNode *XmlNode::addChild( XmlNode *pNode ) 92XmlNode *XmlNode::addChild( XmlNode *pNode )
131{ 93{
132 lChildren.append( pNode ); 94 Child c = { typeNode };
133 lPostContent.append( NULL ); 95 c.pNode = pNode;
134 nCurContent++; 96 lChildren.append( c );
135 pNode->pParent = this; 97 pNode->pParent = this;
136 98
137 return pNode; 99 return pNode;
@@ -142,21 +104,16 @@ XmlNode *XmlNode::getParent()
142 return pParent; 104 return pParent;
143} 105}
144 106
145void XmlNode::addProperty( const char *sName, const char *sValue ) 107void XmlNode::addProperty( const Bu::FString &sName, const Bu::FString &sValue )
146{ 108{
147 std::string *pName = new std::string( sName ); 109 hProperties.insert( sName, sValue );
148 std::string *pValue = new std::string( sValue );
149
150 hProperties.insert( pName->c_str(), pValue->c_str() );
151 lPropNames.append( pName );
152 lPropValues.append( pValue );
153} 110}
154 111
155int XmlNode::getNumProperties() 112int XmlNode::getNumProperties()
156{ 113{
157 return lPropNames.getSize(); 114 return hProperties.size();
158} 115}
159 116/*
160const char *XmlNode::getPropertyName( int nIndex ) 117const char *XmlNode::getPropertyName( int nIndex )
161{ 118{
162 std::string *tmp = ((std::string *)lPropNames[nIndex]); 119 std::string *tmp = ((std::string *)lPropNames[nIndex]);
@@ -172,15 +129,12 @@ const char *XmlNode::getProperty( int nIndex )
172 return NULL; 129 return NULL;
173 return tmp->c_str(); 130 return tmp->c_str();
174} 131}
175 132*/
176const char *XmlNode::getProperty( const char *sName ) 133Bu::FString XmlNode::getProperty( const Bu::FString &sName )
177{ 134{
178 const char *tmp = (const char *)hProperties[sName]; 135 return hProperties[sName];
179 if( tmp == NULL )
180 return NULL;
181 return tmp;
182} 136}
183 137/*
184void XmlNode::deleteProperty( int nIndex ) 138void XmlNode::deleteProperty( int nIndex )
185{ 139{
186 hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); 140 hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() );
@@ -194,29 +148,33 @@ void XmlNode::deleteProperty( int nIndex )
194 148
195bool XmlNode::hasChildren() 149bool XmlNode::hasChildren()
196{ 150{
197 return lChildren.getSize()>0; 151 return hChildren.getSize()>0;
198} 152}*/
199 153
200int XmlNode::getNumChildren() 154int XmlNode::getNumChildren()
201{ 155{
202 return lChildren.getSize(); 156 return lChildren.getSize();
203} 157}
204 158/*
205XmlNode *XmlNode::getChild( int nIndex ) 159XmlNode *XmlNode::getChild( int nIndex )
206{ 160{
207 return (XmlNode *)lChildren[nIndex]; 161 return (XmlNode *)lChildren[nIndex];
208} 162}
209 163*/
210XmlNode *XmlNode::getChild( const char *sName, int nSkip ) 164XmlNode *XmlNode::getChild( const Bu::FString &sName, int nSkip )
211{ 165{
212 return (XmlNode *)hChildren.get( sName, nSkip ); 166 if( !hChildren.has( sName ) )
167 return NULL;
168
169 Bu::List<XmlNode *>::iterator i = hChildren[sName]->begin();
170 return *i;
213} 171}
214 172
215const char *XmlNode::getName() 173Bu::FString XmlNode::getName()
216{ 174{
217 return sName.c_str(); 175 return sName;
218} 176}
219 177/*
220void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) 178void XmlNode::deleteNode( int nIndex, const char *sReplacementText )
221{ 179{
222 XmlNode *xRet = detatchNode( nIndex, sReplacementText ); 180 XmlNode *xRet = detatchNode( nIndex, sReplacementText );
@@ -442,4 +400,4 @@ void XmlNode::deleteNodeKeepChildren( int nIndex )
442void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) 400void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode )
443{ 401{
444} 402}
445 403*/
diff --git a/src/xmlnode.h b/src/xmlnode.h
index 7525306..c895cd8 100644
--- a/src/xmlnode.h
+++ b/src/xmlnode.h
@@ -2,8 +2,9 @@
2#define XMLNODE 2#define XMLNODE
3 3
4#include <iostream> 4#include <iostream>
5#include "linkedlist.h" 5#include "bu/list.h"
6#include "hashtable.h" 6#include "bu/hash.h"
7#include "bu/fstring.h"
7 8
8/** 9/**
9 * Maintains all data pertient to an XML node, including sub-nodes and content. 10 * Maintains all data pertient to an XML node, including sub-nodes and content.
@@ -25,9 +26,8 @@ public:
25 *@param sContent The initial content string. 26 *@param sContent The initial content string.
26 */ 27 */
27 XmlNode( 28 XmlNode(
28 const char *sName=NULL, 29 const Bu::FString &sName,
29 XmlNode *pParent = NULL, 30 XmlNode *pParent=NULL
30 const char *sContent=NULL
31 ); 31 );
32 32
33 /** 33 /**
@@ -39,7 +39,7 @@ public:
39 * Change the name of the node. 39 * Change the name of the node.
40 *@param sName The new name of the node. 40 *@param sName The new name of the node.
41 */ 41 */
42 void setName( const char *sName ); 42 //void setName( const char *sName );
43 43
44 /** 44 /**
45 * Construct a new node and add it as a child to this node, also return a 45 * Construct a new node and add it as a child to this node, also return a
@@ -48,7 +48,7 @@ public:
48 *@param sContent The initial content of the new node. 48 *@param sContent The initial content of the new node.
49 *@returns A pointer to the newly created child node. 49 *@returns A pointer to the newly created child node.
50 */ 50 */
51 XmlNode *addChild( const char *sName, const char *sContent=NULL ); 51 XmlNode *addChild( const Bu::FString &sName );
52 52
53 /** 53 /**
54 * Add an already created XmlNode as a child to this node. The new child 54 * Add an already created XmlNode as a child to this node. The new child
@@ -65,7 +65,7 @@ public:
65 * in use will overwrite that property. 65 * in use will overwrite that property.
66 *@param sValue The textual value of the property. 66 *@param sValue The textual value of the property.
67 */ 67 */
68 void addProperty( const char *sName, const char *sValue ); 68 void addProperty( const Bu::FString &sName, const Bu::FString &sValue );
69 69
70 /** 70 /**
71 * Get a pointer to the parent node, if any. 71 * Get a pointer to the parent node, if any.
@@ -86,14 +86,6 @@ public:
86 int getNumChildren(); 86 int getNumChildren();
87 87
88 /** 88 /**
89 * Get a child node at a specific index.
90 *@param nIndex The zero-based index of the child to retreive.
91 *@returns A pointer to the child, or NULL if you requested an invalid
92 * index.
93 */
94 XmlNode *getChild( int nIndex );
95
96 /**
97 * Get a child with the specified name, and possibly skip value. For an 89 * Get a child with the specified name, and possibly skip value. For an
98 * explination of skip values see the HashTable. 90 * explination of skip values see the HashTable.
99 *@param sName The name of the child to find. 91 *@param sName The name of the child to find.
@@ -101,14 +93,14 @@ public:
101 *@returns A pointer to the child, or NULL if no child with that name was 93 *@returns A pointer to the child, or NULL if no child with that name was
102 * found. 94 * found.
103 */ 95 */
104 XmlNode *getChild( const char *sName, int nSkip=0 ); 96 XmlNode *getChild( const Bu::FString &sName, int nSkip=0 );
105 97
106 /** 98 /**
107 * Get a pointer to the name of this node. Do not change this, use setName 99 * Get a pointer to the name of this node. Do not change this, use setName
108 * instead. 100 * instead.
109 *@returns A pointer to the name of this node. 101 *@returns A pointer to the name of this node.
110 */ 102 */
111 const char *getName(); 103 Bu::FString getName();
112 104
113 /** 105 /**
114 * Set the content of this node, optionally at a specific index. Using the 106 * Set the content of this node, optionally at a specific index. Using the
@@ -116,14 +108,7 @@ public:
116 *@param sContent The content string to use. 108 *@param sContent The content string to use.
117 *@param nIndex The index of the content. 109 *@param nIndex The index of the content.
118 */ 110 */
119 void setContent( const char *sContent, int nIndex=-1 ); 111 //void setContent( const char *sContent, int nIndex=-1 );
120
121 /**
122 * Get the content string at a given index, or zero for initial content.
123 *@param nIndex The index of the content.
124 *@returns A pointer to the content at that location.
125 */
126 const char *getContent( int nIndex = 0 );
127 112
128 /** 113 /**
129 * Get the number of properties in this node. 114 * Get the number of properties in this node.
@@ -132,36 +117,12 @@ public:
132 int getNumProperties(); 117 int getNumProperties();
133 118
134 /** 119 /**
135 * Get a property's name by index.
136 *@param nIndex The index of the property to examine.
137 *@returns A pointer to the name of the property specified, or NULL if none
138 * found.
139 */
140 const char *getPropertyName( int nIndex );
141
142 /**
143 * Get a proprty's value by index.
144 *@param nIndex The index of the property to examine.
145 *@returns A pointer to the value of the property specified, or NULL if none
146 * found.
147 */
148 const char *getProperty( int nIndex );
149
150 /**
151 * Get a propery's value by name. 120 * Get a propery's value by name.
152 *@param sName The name of the property to examine. 121 *@param sName The name of the property to examine.
153 *@returns A pointer to the value of the property specified, or NULL if none 122 *@returns A pointer to the value of the property specified, or NULL if none
154 * found. 123 * found.
155 */ 124 */
156 const char *getProperty( const char *sName ); 125 Bu::FString getProperty( const Bu::FString &sName );
157
158 /**
159 * Delete a property by index.
160 *@param nIndex The index of the property to delete.
161 *@returns True if the property was found and deleted, false if it wasn't
162 * found.
163 */
164 void deleteProperty( int nIndex );
165 126
166 /** 127 /**
167 * Delete a child node, possibly replacing it with some text. This actually 128 * Delete a child node, possibly replacing it with some text. This actually
@@ -171,7 +132,7 @@ public:
171 *@returns True of the node was found, and deleted, false if it wasn't 132 *@returns True of the node was found, and deleted, false if it wasn't
172 * found. 133 * found.
173 */ 134 */
174 void deleteNode( int nIndex, const char *sReplacementText = NULL ); 135 //void deleteNode( int nIndex, const char *sReplacementText = NULL );
175 136
176 /** 137 /**
177 * Delete a given node, but move all of it's children and content up to 138 * Delete a given node, but move all of it's children and content up to
@@ -180,7 +141,7 @@ public:
180 *@param nIndex The node to delete. 141 *@param nIndex The node to delete.
181 *@returns True if the node was found and deleted, false if it wasn't. 142 *@returns True if the node was found and deleted, false if it wasn't.
182 */ 143 */
183 void deleteNodeKeepChildren( int nIndex ); 144 //void deleteNodeKeepChildren( int nIndex );
184 145
185 /** 146 /**
186 * Detatch a given child node from this node. This effectively works just 147 * Detatch a given child node from this node. This effectively works just
@@ -192,7 +153,7 @@ public:
192 *@returns A pointer to the newly detatched node, which then passes 153 *@returns A pointer to the newly detatched node, which then passes
193 * ownership to the caller. 154 * ownership to the caller.
194 */ 155 */
195 XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); 156 //XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL );
196 157
197 /** 158 /**
198 * Replace a given node with a different node that is not currently owned by 159 * Replace a given node with a different node that is not currently owned by
@@ -201,7 +162,7 @@ public:
201 *@param pNewNode The new node to replace the old node with. 162 *@param pNewNode The new node to replace the old node with.
202 *@returns True if the node was found and replaced, false if it wasn't. 163 *@returns True if the node was found and replaced, false if it wasn't.
203 */ 164 */
204 void replaceNode( int nIndex, XmlNode *pNewNode ); 165 //void replaceNode( int nIndex, XmlNode *pNewNode );
205 166
206 /** 167 /**
207 * Replace a given node with the children and content of a given node. 168 * Replace a given node with the children and content of a given node.
@@ -210,24 +171,34 @@ public:
210 * replace the node specified by nIndex. 171 * replace the node specified by nIndex.
211 *@returns True if the node was found and replaced, false if it wasn't. 172 *@returns True if the node was found and replaced, false if it wasn't.
212 */ 173 */
213 void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); 174 //void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode );
214 175
215 /** 176 /**
216 * Get a copy of this node and all children. getCopy is recursive, so 177 * Get a copy of this node and all children. getCopy is recursive, so
217 * beware copying large trees of xml. 178 * beware copying large trees of xml.
218 *@returns A newly created copy of this node and all of it's children. 179 *@returns A newly created copy of this node and all of it's children.
219 */ 180 */
220 XmlNode *getCopy(); 181 //XmlNode *getCopy();
182
183 enum ChildType
184 {
185 typeNode,
186 typeContent
187 };
221 188
222private: 189private:
223 std::string sName; /**< The name of the node. */ 190 typedef struct
224 std::string *sPreContent; /**< The content that goes before any node. */ 191 {
225 LinkedList lChildren; /**< The children. */ 192 uint8_t nType;
226 LinkedList lPostContent; /**< The content that comes after children. */ 193 union {
227 HashTable hProperties; /**< Property hashtable. */ 194 XmlNode *pNode;
228 HashTable hChildren; /**< Children hashtable. */ 195 Bu::FString *pContent;
229 LinkedList lPropNames; /**< List of property names. */ 196 };
230 LinkedList lPropValues; /**< List of property values. */ 197 } Child;
198 Bu::FString sName; /**< The name of the node. */
199 Bu::List<Child> lChildren; /**< The children. */
200 Bu::Hash<Bu::FString, Bu::FString> hProperties; /**< Property hashtable. */
201 Bu::Hash<Bu::FString, Bu::List<XmlNode *> > hChildren; /**< Children hashtable. */
231 XmlNode *pParent; /**< A pointer to the parent of this node. */ 202 XmlNode *pParent; /**< A pointer to the parent of this node. */
232 int nCurContent; /**< The current content we're on, for using the -1 on 203 int nCurContent; /**< The current content we're on, for using the -1 on
233 setContent. */ 204 setContent. */
diff --git a/src/xmlreader.cpp b/src/xmlreader.cpp
index 18df69c..38cad5f 100644
--- a/src/xmlreader.cpp
+++ b/src/xmlreader.cpp
@@ -1,32 +1,49 @@
1#include "xmlreader.h" 1#include "bu/xmlreader.h"
2#include "exceptions.h" 2#include "bu/exceptions.h"
3#include <string.h> 3#include <string.h>
4#include "hashfunctionstring.h"
5 4
6XmlReader::XmlReader( bool bStrip ) : 5XmlReader::XmlReader( Bu::Stream &sIn, bool bStrip ) :
7 bStrip( bStrip ), 6 sIn( sIn ),
8 htEntity( new HashFunctionString(), 11 ) 7 bStrip( bStrip )
9{ 8{
9 buildDoc();
10} 10}
11 11
12XmlReader::~XmlReader() 12XmlReader::~XmlReader()
13{ 13{
14 void *i = htEntity.getFirstItemPos(); 14}
15 while( (i = htEntity.getNextItemPos( i ) ) ) 15
16char XmlReader::getChar( int nIndex )
17{
18 if( sBuf.getSize() <= nIndex )
16 { 19 {
17 free( (char *)(htEntity.getItemID( i )) ); 20 int nInc = nIndex-sBuf.getSize()+1;
18 delete (StaticString *)htEntity.getItemData( i ); 21 char *buf = new char[nInc];
22 sIn.read( buf, nInc );
23 sBuf.append( buf, nInc );
24 delete[] buf;
19 } 25 }
26
27 return sBuf[nIndex];
20} 28}
21 29
22void XmlReader::addEntity( const char *name, const char *value ) 30void XmlReader::usedChar( int nAmnt )
23{ 31{
24 if( htEntity[name] ) return; 32 if( nAmnt >= sBuf.getSize() )
25 33 {
26 char *sName = strdup( name ); 34 sBuf.clear();
27 StaticString *sValue = new StaticString( value ); 35 }
36 else
37 {
38 char *s = sBuf.getStr();
39 memcpy( s, s+nAmnt, sBuf.getSize()-nAmnt );
40 sBuf.resize( sBuf.getSize()-nAmnt );
41 }
42}
28 43
29 htEntity.insert( sName, sValue ); 44void XmlReader::addEntity( const Bu::FString &name, const Bu::FString &value )
45{
46 htEntity[name] = value;
30} 47}
31 48
32#define gcall( x ) if( x == false ) return false; 49#define gcall( x ) if( x == false ) return false;
@@ -99,7 +116,7 @@ void XmlReader::entity()
99 { 116 {
100 usedChar( 2 ); 117 usedChar( 2 );
101 ws(); 118 ws();
102 std::string buf; 119 Bu::FString buf;
103 for(;;) 120 for(;;)
104 { 121 {
105 char chr = getChar(); 122 char chr = getChar();
@@ -111,7 +128,7 @@ void XmlReader::entity()
111 if( strcmp( buf.c_str(), "ENTITY") == 0 ) 128 if( strcmp( buf.c_str(), "ENTITY") == 0 )
112 { 129 {
113 ws(); 130 ws();
114 std::string name; 131 Bu::FString name;
115 for(;;) 132 for(;;)
116 { 133 {
117 char chr = getChar(); 134 char chr = getChar();
@@ -124,21 +141,19 @@ void XmlReader::entity()
124 usedChar(); 141 usedChar();
125 if( quot != '\'' && quot != '\"' ) 142 if( quot != '\'' && quot != '\"' )
126 { 143 {
127 throw XmlException( 144 throw Bu::XmlException(
128 "Only quoted entity values are supported." 145 "Only quoted entity values are supported."
129 ); 146 );
130 } 147 }
131 std::string value; 148 Bu::FString value;
132 for(;;) 149 for(;;)
133 { 150 {
134 char chr = getChar(); 151 char chr = getChar();
135 usedChar(); 152 usedChar();
136 if( chr == '&' ) 153 if( chr == '&' )
137 { 154 {
138 StaticString *tmp = getEscape(); 155 Bu::FString tmp = getEscape();
139 if( tmp == NULL ) throw XmlException("Entity thing"); 156 value += tmp;
140 value += tmp->getString();
141 delete tmp;
142 } 157 }
143 else if( chr == quot ) 158 else if( chr == quot )
144 { 159 {
@@ -158,7 +173,7 @@ void XmlReader::entity()
158 } 173 }
159 else 174 else
160 { 175 {
161 throw XmlException( 176 throw Bu::XmlException(
162 "Malformed ENTITY: unexpected '%c' found.", 177 "Malformed ENTITY: unexpected '%c' found.",
163 getChar() 178 getChar()
164 ); 179 );
@@ -166,7 +181,7 @@ void XmlReader::entity()
166 } 181 }
167 else 182 else
168 { 183 {
169 throw XmlException( 184 throw Bu::XmlException(
170 "Unsupported header symbol: %s", 185 "Unsupported header symbol: %s",
171 buf.c_str() 186 buf.c_str()
172 ); 187 );
@@ -203,12 +218,12 @@ bool XmlReader::node()
203 } 218 }
204 else 219 else
205 { 220 {
206 throw XmlException("Close node in singleNode malformed!"); 221 throw Bu::XmlException("Close node in singleNode malformed!");
207 } 222 }
208 } 223 }
209 else 224 else
210 { 225 {
211 throw XmlException("Close node expected, but not found."); 226 throw Bu::XmlException("Close node expected, but not found.");
212 return false; 227 return false;
213 } 228 }
214 229
@@ -224,7 +239,7 @@ bool XmlReader::startNode()
224 if( getChar() == '/' ) 239 if( getChar() == '/' )
225 { 240 {
226 // Heh, it's actually a close node, go figure 241 // Heh, it's actually a close node, go figure
227 FlexBuf fbName; 242 Bu::FString sName;
228 usedChar(); 243 usedChar();
229 gcall( ws() ); 244 gcall( ws() );
230 245
@@ -235,19 +250,19 @@ bool XmlReader::startNode()
235 { 250 {
236 // Here we actually compare the name we got to the name 251 // Here we actually compare the name we got to the name
237 // we already set, they have to match exactly. 252 // we already set, they have to match exactly.
238 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) 253 if( getCurrent()->getName() == sName )
239 { 254 {
240 closeNode(); 255 closeNode();
241 break; 256 break;
242 } 257 }
243 else 258 else
244 { 259 {
245 throw XmlException("Got a mismatched node close tag."); 260 throw Bu::XmlException("Got a mismatched node close tag.");
246 } 261 }
247 } 262 }
248 else 263 else
249 { 264 {
250 fbName.appendData( chr ); 265 sName += chr;
251 usedChar(); 266 usedChar();
252 } 267 }
253 } 268 }
@@ -260,13 +275,13 @@ bool XmlReader::startNode()
260 } 275 }
261 else 276 else
262 { 277 {
263 throw XmlException("Got extra junk data instead of node close tag."); 278 throw Bu::XmlException("Got extra junk data instead of node close tag.");
264 } 279 }
265 } 280 }
266 else 281 else
267 { 282 {
268 // We're good, format is consistant 283 // We're good, format is consistant
269 addNode(); 284 //addNode();
270 285
271 // Skip extra whitespace 286 // Skip extra whitespace
272 gcall( ws() ); 287 gcall( ws() );
@@ -278,7 +293,7 @@ bool XmlReader::startNode()
278 } 293 }
279 else 294 else
280 { 295 {
281 throw XmlException("Expected to find node opening char, '<'."); 296 throw Bu::XmlException("Expected to find node opening char, '<'.");
282 } 297 }
283 298
284 return true; 299 return true;
@@ -286,19 +301,19 @@ bool XmlReader::startNode()
286 301
287bool XmlReader::name() 302bool XmlReader::name()
288{ 303{
289 FlexBuf fbName; 304 Bu::FString sName;
290 305
291 while( true ) 306 while( true )
292 { 307 {
293 char chr = getChar(); 308 char chr = getChar();
294 if( isws( chr ) || chr == '>' || chr == '/' ) 309 if( isws( chr ) || chr == '>' || chr == '/' )
295 { 310 {
296 setName( fbName.getData() ); 311 addNode( sName );
297 return true; 312 return true;
298 } 313 }
299 else 314 else
300 { 315 {
301 fbName.appendData( chr ); 316 sName += chr;
302 usedChar(); 317 usedChar();
303 } 318 }
304 } 319 }
@@ -325,7 +340,7 @@ bool XmlReader::paramlist()
325 return true; 340 return true;
326} 341}
327 342
328StaticString *XmlReader::getEscape() 343Bu::FString XmlReader::getEscape()
329{ 344{
330 if( getChar( 1 ) == '#' ) 345 if( getChar( 1 ) == '#' )
331 { 346 {
@@ -349,12 +364,12 @@ StaticString *XmlReader::getEscape()
349 buf[0] = (char)strtol( buf, (char **)NULL, base ); 364 buf[0] = (char)strtol( buf, (char **)NULL, base );
350 buf[1] = '\0'; 365 buf[1] = '\0';
351 366
352 return new StaticString( buf ); 367 return buf;
353 } 368 }
354 else 369 else
355 { 370 {
356 // ...otherwise replace with the appropriate string... 371 // ...otherwise replace with the appropriate string...
357 std::string buf; 372 Bu::FString buf;
358 usedChar(); 373 usedChar();
359 for(;;) 374 for(;;)
360 { 375 {
@@ -364,18 +379,14 @@ StaticString *XmlReader::getEscape()
364 buf += cbuf; 379 buf += cbuf;
365 } 380 }
366 381
367 StaticString *tmp = (StaticString *)htEntity[buf.c_str()]; 382 return htEntity[buf];
368 if( tmp == NULL ) return NULL;
369
370 StaticString *ret = new StaticString( *tmp );
371 return ret;
372 } 383 }
373} 384}
374 385
375bool XmlReader::param() 386bool XmlReader::param()
376{ 387{
377 FlexBuf fbName; 388 Bu::FString sName;
378 FlexBuf fbValue; 389 Bu::FString sValue;
379 390
380 while( true ) 391 while( true )
381 { 392 {
@@ -386,7 +397,7 @@ bool XmlReader::param()
386 } 397 }
387 else 398 else
388 { 399 {
389 fbName.appendData( chr ); 400 sName.append( chr );
390 usedChar(); 401 usedChar();
391 } 402 }
392 } 403 }
@@ -411,21 +422,18 @@ bool XmlReader::param()
411 if( chr == '"' ) 422 if( chr == '"' )
412 { 423 {
413 usedChar(); 424 usedChar();
414 addProperty( fbName.getData(), fbValue.getData() ); 425 addProperty( sName.getStr(), sValue.getStr() );
415 return true; 426 return true;
416 } 427 }
417 else 428 else
418 { 429 {
419 if( chr == '&' ) 430 if( chr == '&' )
420 { 431 {
421 StaticString *tmp = getEscape(); 432 sValue += getEscape();
422 if( tmp == NULL ) return false;
423 fbValue.appendData( tmp->getString() );
424 delete tmp;
425 } 433 }
426 else 434 else
427 { 435 {
428 fbValue.appendData( chr ); 436 sValue += chr;
429 usedChar(); 437 usedChar();
430 } 438 }
431 } 439 }
@@ -439,21 +447,18 @@ bool XmlReader::param()
439 chr = getChar(); 447 chr = getChar();
440 if( isws( chr ) || chr == '/' || chr == '>' ) 448 if( isws( chr ) || chr == '/' || chr == '>' )
441 { 449 {
442 addProperty( fbName.getData(), fbValue.getData() ); 450 addProperty( sName.getStr(), sValue.getStr() );
443 return true; 451 return true;
444 } 452 }
445 else 453 else
446 { 454 {
447 if( chr == '&' ) 455 if( chr == '&' )
448 { 456 {
449 StaticString *tmp = getEscape(); 457 sValue += getEscape();
450 if( tmp == NULL ) return false;
451 fbValue.appendData( tmp->getString() );
452 delete tmp;
453 } 458 }
454 else 459 else
455 { 460 {
456 fbValue.appendData( chr ); 461 sValue += chr;
457 usedChar(); 462 usedChar();
458 } 463 }
459 } 464 }
@@ -462,7 +467,7 @@ bool XmlReader::param()
462 } 467 }
463 else 468 else
464 { 469 {
465 throw XmlException("Expected an equals to seperate the params."); 470 throw Bu::XmlException("Expected an equals to seperate the params.");
466 return false; 471 return false;
467 } 472 }
468 473
@@ -471,7 +476,7 @@ bool XmlReader::param()
471 476
472bool XmlReader::content() 477bool XmlReader::content()
473{ 478{
474 FlexBuf fbContent; 479 Bu::FString sContent;
475 480
476 if( bStrip ) gcall( ws() ); 481 if( bStrip ) gcall( ws() );
477 482
@@ -482,37 +487,37 @@ bool XmlReader::content()
482 { 487 {
483 if( getChar(1) == '/' ) 488 if( getChar(1) == '/' )
484 { 489 {
485 if( fbContent.getLength() > 0 ) 490 if( sContent.getSize() > 0 )
486 { 491 {
487 if( bStrip ) 492 if( bStrip )
488 { 493 {
489 int j; 494 int j;
490 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); 495 for( j = sContent.getSize()-1; isws(sContent[j]); j-- );
491 ((char *)fbContent.getData())[j+1] = '\0'; 496 sContent[j+1] = '\0';
492 } 497 }
493 setContent( fbContent.getData() ); 498 setContent( sContent.getStr() );
494 } 499 }
495 usedChar( 2 ); 500 usedChar( 2 );
496 gcall( ws() ); 501 gcall( ws() );
497 FlexBuf fbName; 502 Bu::FString sName;
498 while( true ) 503 while( true )
499 { 504 {
500 chr = getChar(); 505 chr = getChar();
501 if( isws( chr ) || chr == '>' ) 506 if( isws( chr ) || chr == '>' )
502 { 507 {
503 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) 508 if( !strcasecmp( getCurrent()->getName().getStr(), sName.getStr() ) )
504 { 509 {
505 closeNode(); 510 closeNode();
506 break; 511 break;
507 } 512 }
508 else 513 else
509 { 514 {
510 throw XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName(), fbName.getData() ); 515 throw Bu::XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName().getStr(), sName.getStr() );
511 } 516 }
512 } 517 }
513 else 518 else
514 { 519 {
515 fbName.appendData( chr ); 520 sName += chr;
516 usedChar(); 521 usedChar();
517 } 522 }
518 } 523 }
@@ -524,7 +529,7 @@ bool XmlReader::content()
524 } 529 }
525 else 530 else
526 { 531 {
527 throw XmlException("Malformed close tag."); 532 throw Bu::XmlException("Malformed close tag.");
528 } 533 }
529 } 534 }
530 else if( getChar(1) == '!' ) 535 else if( getChar(1) == '!' )
@@ -534,7 +539,7 @@ bool XmlReader::content()
534 getChar(3) != '-' ) 539 getChar(3) != '-' )
535 { 540 {
536 // Not a valid XML comment 541 // Not a valid XML comment
537 throw XmlException("Malformed comment start tag found."); 542 throw Bu::XmlException("Malformed comment start tag found.");
538 } 543 }
539 544
540 usedChar( 4 ); 545 usedChar( 4 );
@@ -549,7 +554,7 @@ bool XmlReader::content()
549 // The next one has to be a '>' now 554 // The next one has to be a '>' now
550 if( getChar( 2 ) != '>' ) 555 if( getChar( 2 ) != '>' )
551 { 556 {
552 throw XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); 557 throw Bu::XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment.");
553 } 558 }
554 usedChar( 3 ); 559 usedChar( 3 );
555 break; 560 break;
@@ -569,16 +574,16 @@ bool XmlReader::content()
569 } 574 }
570 else 575 else
571 { 576 {
572 if( fbContent.getLength() > 0 ) 577 if( sContent.getSize() > 0 )
573 { 578 {
574 if( bStrip ) 579 if( bStrip )
575 { 580 {
576 int j; 581 int j;
577 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); 582 for( j = sContent.getSize()-1; isws(sContent[j]); j-- );
578 ((char *)fbContent.getData())[j+1] = '\0'; 583 sContent[j+1] = '\0';
579 } 584 }
580 setContent( fbContent.getData() ); 585 setContent( sContent.getStr() );
581 fbContent.clearData(); 586 sContent.clear();
582 } 587 }
583 gcall( node() ); 588 gcall( node() );
584 } 589 }
@@ -587,14 +592,11 @@ bool XmlReader::content()
587 } 592 }
588 else if( chr == '&' ) 593 else if( chr == '&' )
589 { 594 {
590 StaticString *tmp = getEscape(); 595 sContent += getEscape();
591 if( tmp == NULL ) return false;
592 fbContent.appendData( tmp->getString() );
593 delete tmp;
594 } 596 }
595 else 597 else
596 { 598 {
597 fbContent.appendData( chr ); 599 sContent += chr;
598 usedChar(); 600 usedChar();
599 } 601 }
600 } 602 }
diff --git a/src/xmlreader.h b/src/xmlreader.h
index c8f7202..7c85ddb 100644
--- a/src/xmlreader.h
+++ b/src/xmlreader.h
@@ -2,10 +2,10 @@
2#define XMLREADER 2#define XMLREADER
3 3
4#include <stdio.h> 4#include <stdio.h>
5#include "xmldocument.h" 5#include "bu/xmldocument.h"
6#include "flexbuf.h" 6#include "bu/hash.h"
7#include "hashtable.h" 7#include "bu/fstring.h"
8#include "staticstring.h" 8#include "bu/stream.h"
9 9
10/** 10/**
11 * Takes care of reading in xml formatted data from a file. This could/should 11 * Takes care of reading in xml formatted data from a file. This could/should
@@ -32,7 +32,7 @@ public:
32 * in content, a-la html. 32 * in content, a-la html.
33 *@param bStrip Strip out leading and trailing whitespace? 33 *@param bStrip Strip out leading and trailing whitespace?
34 */ 34 */
35 XmlReader( bool bStrip=false ); 35 XmlReader( Bu::Stream &sIn, bool bStrip=false );
36 36
37 /** 37 /**
38 * Destroy this XmlReader. 38 * Destroy this XmlReader.
@@ -54,12 +54,12 @@ private:
54 *@returns A single character at the requested position, or 0 for end of 54 *@returns A single character at the requested position, or 0 for end of
55 * stream. 55 * stream.
56 */ 56 */
57 virtual char getChar( int nIndex = 0 ) = 0; 57 virtual char getChar( int nIndex = 0 );
58 58
59 /** 59 /**
60 * Called to increment the current stream position by a single character. 60 * Called to increment the current stream position by a single character.
61 */ 61 */
62 virtual void usedChar( int nAmnt = 1) = 0; 62 virtual void usedChar( int nAmnt = 1 );
63 63
64 /** 64 /**
65 * Automoton function: is whitespace. 65 * Automoton function: is whitespace.
@@ -108,9 +108,9 @@ private:
108 *@param name The name of the entity 108 *@param name The name of the entity
109 *@param value The value of the entity 109 *@param value The value of the entity
110 */ 110 */
111 void addEntity( const char *name, const char *value ); 111 void addEntity( const Bu::FString &name, const Bu::FString &value );
112 112
113 StaticString *getEscape(); 113 Bu::FString getEscape();
114 114
115 /** 115 /**
116 * Automoton function: paramlist. Processes a list of node params. 116 * Automoton function: paramlist. Processes a list of node params.
@@ -130,12 +130,15 @@ private:
130 */ 130 */
131 bool content(); 131 bool content();
132 132
133 FlexBuf fbContent; /**< buffer for the current node's content. */ 133 Bu::FString sContent; /**< buffer for the current node's content. */
134 FlexBuf fbParamName; /**< buffer for the current param's name. */ 134 Bu::FString sParamName; /**< buffer for the current param's name. */
135 FlexBuf fbParamValue; /**< buffer for the current param's value. */ 135 Bu::FString sParamValue; /**< buffer for the current param's value. */
136 bool bStrip; /**< Are we stripping whitespace? */ 136 Bu::Stream &sIn;
137 bool bStrip; /**< Are we stripping whitespace? */
137 138
138 HashTable htEntity; /**< Entity type definitions. */ 139 Bu::Hash<Bu::FString,Bu::FString> htEntity; /**< Entity type definitions. */
140
141 Bu::FString sBuf;
139}; 142};
140 143
141#endif 144#endif
diff --git a/src/xmlwriter.cpp b/src/xmlwriter.cpp
index 56880b6..7dc6ca9 100644
--- a/src/xmlwriter.cpp
+++ b/src/xmlwriter.cpp
@@ -2,17 +2,10 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include "xmlwriter.h" 3#include "xmlwriter.h"
4 4
5XmlWriter::XmlWriter( const char *sIndent, XmlNode *pRoot ) : 5XmlWriter::XmlWriter( const Bu::FString &sIndent, XmlNode *pRoot ) :
6 XmlDocument( pRoot ) 6 XmlDocument( pRoot ),
7 sIndent( sIndent )
7{ 8{
8 if( sIndent == NULL )
9 {
10 this->sIndent = "";
11 }
12 else
13 {
14 this->sIndent = sIndent;
15 }
16} 9}
17 10
18XmlWriter::~XmlWriter() 11XmlWriter::~XmlWriter()
@@ -24,7 +17,7 @@ void XmlWriter::write()
24 write( getRoot(), sIndent.c_str() ); 17 write( getRoot(), sIndent.c_str() );
25} 18}
26 19
27void XmlWriter::write( XmlNode *pRoot, const char *sIndent ) 20void XmlWriter::write( XmlNode *pRoot, const Bu::FString &sIndent )
28{ 21{
29 writeNode( pRoot, 0, sIndent ); 22 writeNode( pRoot, 0, sIndent );
30} 23}
@@ -39,7 +32,7 @@ void XmlWriter::closeNode()
39 } 32 }
40} 33}
41 34
42void XmlWriter::writeIndent( int nIndent, const char *sIndent ) 35void XmlWriter::writeIndent( int nIndent, const Bu::FString &sIndent )
43{ 36{
44 if( sIndent == NULL ) return; 37 if( sIndent == NULL ) return;
45 for( int j = 0; j < nIndent; j++ ) 38 for( int j = 0; j < nIndent; j++ )
@@ -48,26 +41,27 @@ void XmlWriter::writeIndent( int nIndent, const char *sIndent )
48 } 41 }
49} 42}
50 43
51std::string XmlWriter::escape( std::string sIn ) 44Bu::FString XmlWriter::escape( const Bu::FString &sIn )
52{ 45{
53 std::string sOut; 46 Bu::FString sOut;
54 47
55 std::string::const_iterator i; 48 int nMax = sIn.getSize();
56 for( i = sIn.begin(); i != sIn.end(); i++ ) 49 for( int j = 0; j < nMax; j++ )
57 { 50 {
58 if( ((*i >= ' ' && *i <= '9') || 51 char c = sIn[j];
59 (*i >= 'a' && *i <= 'z') || 52 if( ((c >= ' ' && c <= '9') ||
60 (*i >= 'A' && *i <= 'Z') ) && 53 (c >= 'a' && c <= 'z') ||
61 (*i != '\"' && *i != '\'' && *i != '&') 54 (c >= 'A' && c <= 'Z') ) &&
55 (c != '\"' && c != '\'' && c != '&')
62 ) 56 )
63 { 57 {
64 sOut += *i; 58 sOut += c;
65 } 59 }
66 else 60 else
67 { 61 {
68 sOut += "&#"; 62 sOut += "&#";
69 char buf[4]; 63 char buf[4];
70 sprintf( buf, "%u", (unsigned char)*i ); 64 sprintf( buf, "%u", (unsigned char)c );
71 sOut += buf; 65 sOut += buf;
72 sOut += ';'; 66 sOut += ';';
73 } 67 }
@@ -76,19 +70,19 @@ std::string XmlWriter::escape( std::string sIn )
76 return sOut; 70 return sOut;
77} 71}
78 72
79void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ) 73void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent )
80{ 74{
81 for( int j = 0; j < pNode->getNumProperties(); j++ ) 75 for( int j = 0; j < pNode->getNumProperties(); j++ )
82 { 76 {
83 writeString(" "); 77 writeString(" ");
84 writeString( pNode->getPropertyName( j ) ); 78 //writeString( pNode->getPropertyName( j ) );
85 writeString("=\""); 79 writeString("=\"");
86 writeString( escape( pNode->getProperty( j ) ).c_str() ); 80 //writeString( escape( pNode->getProperty( j ) ).c_str() );
87 writeString("\""); 81 writeString("\"");
88 } 82 }
89} 83}
90 84
91void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) 85void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent )
92{ 86{
93 if( pNode->hasChildren() ) 87 if( pNode->hasChildren() )
94 { 88 {
@@ -96,15 +90,15 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
96 writeString("<"); 90 writeString("<");
97 writeString( pNode->getName() ); 91 writeString( pNode->getName() );
98 writeNodeProps( pNode, nIndent, sIndent ); 92 writeNodeProps( pNode, nIndent, sIndent );
99 if( sIndent ) 93 if( sIndent != "" )
100 writeString(">\n"); 94 writeString(">\n");
101 else 95 else
102 writeString(">"); 96 writeString(">");
103 97/*
104 if( pNode->getContent( 0 ) ) 98 if( pNode->getContent( 0 ) )
105 { 99 {
106 writeIndent( nIndent+1, sIndent ); 100 writeIndent( nIndent+1, sIndent );
107 if( sIndent ) 101 if( sIndent != "" )
108 { 102 {
109 writeString( pNode->getContent( 0 ) ); 103 writeString( pNode->getContent( 0 ) );
110 writeString("\n"); 104 writeString("\n");
@@ -129,9 +123,9 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
129 writeString( pNode->getContent( j+1 ) ); 123 writeString( pNode->getContent( j+1 ) );
130 } 124 }
131 } 125 }
132 126*/
133 writeIndent( nIndent, sIndent ); 127 writeIndent( nIndent, sIndent );
134 if( sIndent ) 128 if( sIndent != "" )
135 { 129 {
136 writeString("</"); 130 writeString("</");
137 writeString( pNode->getName() ); 131 writeString( pNode->getName() );
@@ -143,7 +137,7 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
143 writeString( pNode->getName() ); 137 writeString( pNode->getName() );
144 writeString(">"); 138 writeString(">");
145 } 139 }
146 } 140 }/*
147 else if( pNode->getContent() ) 141 else if( pNode->getContent() )
148 { 142 {
149 writeIndent( nIndent, sIndent ); 143 writeIndent( nIndent, sIndent );
@@ -157,14 +151,14 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
157 writeString(">"); 151 writeString(">");
158 if( sIndent ) 152 if( sIndent )
159 writeString("\n"); 153 writeString("\n");
160 } 154 }*/
161 else 155 else
162 { 156 {
163 writeIndent( nIndent, sIndent ); 157 writeIndent( nIndent, sIndent );
164 writeString("<"); 158 writeString("<");
165 writeString( pNode->getName() ); 159 writeString( pNode->getName() );
166 writeNodeProps( pNode, nIndent, sIndent ); 160 writeNodeProps( pNode, nIndent, sIndent );
167 if( sIndent ) 161 if( sIndent != "" )
168 writeString("/>\n"); 162 writeString("/>\n");
169 else 163 else
170 writeString("/>"); 164 writeString("/>");
diff --git a/src/xmlwriter.h b/src/xmlwriter.h
index c48e810..7e3c876 100644
--- a/src/xmlwriter.h
+++ b/src/xmlwriter.h
@@ -31,7 +31,7 @@ public:
31 * this to a tab or some spaces it will never effect the content of your 31 * this to a tab or some spaces it will never effect the content of your
32 * file. 32 * file.
33 */ 33 */
34 XmlWriter( const char *sIndent=NULL, XmlNode *pRoot=NULL ); 34 XmlWriter( const Bu::FString &sIndent="", XmlNode *pRoot=NULL );
35 35
36 /** 36 /**
37 * Destroy the writer. 37 * Destroy the writer.
@@ -49,16 +49,16 @@ public:
49 void write(); 49 void write();
50 50
51private: 51private:
52 std::string sIndent; /**< The indent string */ 52 Bu::FString sIndent; /**< The indent string */
53 53
54 std::string escape( std::string sIn ); 54 Bu::FString escape( const Bu::FString &sIn );
55 55
56 /** 56 /**
57 * Write the file. 57 * Write the file.
58 *@param pNode The root node 58 *@param pNode The root node
59 *@param sIndent The indent text. 59 *@param sIndent The indent text.
60 */ 60 */
61 void write( XmlNode *pNode, const char *sIndent=NULL ); 61 void write( XmlNode *pNode, const Bu::FString &sIndent );
62 62
63 /** 63 /**
64 * Write a node in the file, including children. 64 * Write a node in the file, including children.
@@ -66,7 +66,7 @@ private:
66 *@param nIndent The indent level (the number of times to include sIndent) 66 *@param nIndent The indent level (the number of times to include sIndent)
67 *@param sIndent The indent text. 67 *@param sIndent The indent text.
68 */ 68 */
69 void writeNode( XmlNode *pNode, int nIndent, const char *sIndent ); 69 void writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent );
70 70
71 /** 71 /**
72 * Write the properties of a node. 72 * Write the properties of a node.
@@ -74,14 +74,14 @@ private:
74 *@param nIndent The indent level of the containing node 74 *@param nIndent The indent level of the containing node
75 *@param sIndent The indent text. 75 *@param sIndent The indent text.
76 */ 76 */
77 void writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ); 77 void writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent );
78 78
79 /** 79 /**
80 * Called to write the actual indent. 80 * Called to write the actual indent.
81 *@param nIndent The indent level. 81 *@param nIndent The indent level.
82 *@param sIndent The indent text. 82 *@param sIndent The indent text.
83 */ 83 */
84 void writeIndent( int nIndent, const char *sIndent ); 84 void writeIndent( int nIndent, const Bu::FString &sIndent );
85 85
86 /** 86 /**
87 * This is the function that must be overridden in order to use this class. 87 * This is the function that must be overridden in order to use this class.
@@ -90,7 +90,7 @@ private:
90 * will break the XML formatting. 90 * will break the XML formatting.
91 *@param sString The string data to write to the output. 91 *@param sString The string data to write to the output.
92 */ 92 */
93 virtual void writeString( const char *sString ) = 0; 93 virtual void writeString( const Bu::FString &sString ) = 0;
94}; 94};
95 95
96#endif 96#endif