diff options
Diffstat (limited to 'src/old')
-rw-r--r-- | src/old/xmldocument.cpp | 145 | ||||
-rw-r--r-- | src/old/xmldocument.h | 165 | ||||
-rw-r--r-- | src/old/xmlnode.cpp | 403 | ||||
-rw-r--r-- | src/old/xmlnode.h | 207 | ||||
-rw-r--r-- | src/old/xmlreader.cpp | 604 | ||||
-rw-r--r-- | src/old/xmlreader.h | 144 | ||||
-rw-r--r-- | src/old/xmlwriter.cpp | 167 | ||||
-rw-r--r-- | src/old/xmlwriter.h | 96 |
8 files changed, 1931 insertions, 0 deletions
diff --git a/src/old/xmldocument.cpp b/src/old/xmldocument.cpp new file mode 100644 index 0000000..95b9788 --- /dev/null +++ b/src/old/xmldocument.cpp | |||
@@ -0,0 +1,145 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include "xmldocument.h" | ||
4 | |||
5 | XmlDocument::XmlDocument( XmlNode *pRoot ) | ||
6 | { | ||
7 | this->pRoot = pRoot; | ||
8 | pCurrent = NULL; | ||
9 | bCompleted = (pRoot!=NULL); | ||
10 | } | ||
11 | |||
12 | XmlDocument::~XmlDocument() | ||
13 | { | ||
14 | if( pRoot ) | ||
15 | { | ||
16 | delete pRoot; | ||
17 | } | ||
18 | } | ||
19 | |||
20 | void XmlDocument::addNode( const Bu::FString &sName ) | ||
21 | { | ||
22 | if( pRoot == NULL ) | ||
23 | { | ||
24 | // This is the first node, so ignore position and just insert it. | ||
25 | pCurrent = pRoot = new XmlNode( sName ); | ||
26 | } | ||
27 | else | ||
28 | { | ||
29 | pCurrent = pCurrent->addChild( sName ); | ||
30 | } | ||
31 | } | ||
32 | /* | ||
33 | void XmlDocument::setName( const char *sName ) | ||
34 | { | ||
35 | pCurrent->setName( sName ); | ||
36 | }*/ | ||
37 | |||
38 | bool XmlDocument::isCompleted() | ||
39 | { | ||
40 | return bCompleted; | ||
41 | } | ||
42 | |||
43 | XmlNode *XmlDocument::getRoot() | ||
44 | { | ||
45 | return pRoot; | ||
46 | } | ||
47 | |||
48 | XmlNode *XmlDocument::detatchRoot() | ||
49 | { | ||
50 | XmlNode *pTemp = pRoot; | ||
51 | pRoot = NULL; | ||
52 | return pTemp; | ||
53 | } | ||
54 | |||
55 | XmlNode *XmlDocument::getCurrent() | ||
56 | { | ||
57 | return pCurrent; | ||
58 | } | ||
59 | |||
60 | void XmlDocument::closeNode() | ||
61 | { | ||
62 | if( pCurrent != NULL ) | ||
63 | { | ||
64 | pCurrent = pCurrent->getParent(); | ||
65 | |||
66 | if( pCurrent == NULL ) | ||
67 | { | ||
68 | bCompleted = true; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | void XmlDocument::addProperty( const char *sName, const char *sValue ) | ||
74 | { | ||
75 | if( pCurrent ) | ||
76 | { | ||
77 | pCurrent->addProperty( sName, sValue ); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | void XmlDocument::addProperty( const char *sName, const unsigned char nValue ) | ||
82 | { | ||
83 | char buf[12]; | ||
84 | sprintf( buf, "%hhi", nValue ); | ||
85 | addProperty( sName, buf ); | ||
86 | } | ||
87 | |||
88 | void XmlDocument::addProperty( const char *sName, const char nValue ) | ||
89 | { | ||
90 | char buf[12]; | ||
91 | sprintf( buf, "%hhi", nValue ); | ||
92 | addProperty( sName, buf ); | ||
93 | } | ||
94 | |||
95 | void XmlDocument::addProperty( const char *sName, const unsigned short nValue ) | ||
96 | { | ||
97 | char buf[12]; | ||
98 | sprintf( buf, "%hi", nValue ); | ||
99 | addProperty( sName, buf ); | ||
100 | } | ||
101 | |||
102 | void XmlDocument::addProperty( const char *sName, const short nValue ) | ||
103 | { | ||
104 | char buf[12]; | ||
105 | sprintf( buf, "%hi", nValue ); | ||
106 | addProperty( sName, buf ); | ||
107 | } | ||
108 | |||
109 | void XmlDocument::addProperty( const char *sName, const int nValue ) | ||
110 | { | ||
111 | char buf[12]; | ||
112 | sprintf( buf, "%d", nValue ); | ||
113 | addProperty( sName, buf ); | ||
114 | } | ||
115 | |||
116 | void XmlDocument::addProperty( const char *sName, const unsigned long nValue ) | ||
117 | { | ||
118 | char buf[12]; | ||
119 | sprintf( buf, "%li", nValue ); | ||
120 | addProperty( sName, buf ); | ||
121 | } | ||
122 | |||
123 | void XmlDocument::addProperty( const char *sName, const long nValue ) | ||
124 | { | ||
125 | char buf[12]; | ||
126 | sprintf( buf, "%li", nValue ); | ||
127 | addProperty( sName, buf ); | ||
128 | } | ||
129 | |||
130 | void XmlDocument::addProperty( const char *sName, const double dValue ) | ||
131 | { | ||
132 | char buf[40]; | ||
133 | sprintf( buf, "%f", dValue ); | ||
134 | addProperty( sName, buf ); | ||
135 | } | ||
136 | |||
137 | void XmlDocument::setContent( const char *sContent ) | ||
138 | { | ||
139 | if( pCurrent ) | ||
140 | { | ||
141 | printf("XmlDocument::setContent: not yet implemented.\n"); | ||
142 | //pCurrent->setContent( sContent ); | ||
143 | } | ||
144 | } | ||
145 | |||
diff --git a/src/old/xmldocument.h b/src/old/xmldocument.h new file mode 100644 index 0000000..e0c36eb --- /dev/null +++ b/src/old/xmldocument.h | |||
@@ -0,0 +1,165 @@ | |||
1 | #ifndef XMLDOCUMENT | ||
2 | #define XMLDOCUMENT | ||
3 | |||
4 | #include "xmlnode.h" | ||
5 | |||
6 | /** | ||
7 | * Keeps track of an easily managed set of XmlNode information. Allows simple | ||
8 | * operations for logical writing to and reading from XML structures. Using | ||
9 | * already formed structures is simply done through the XmlNode structures, | ||
10 | * and the getRoot function here. Creation is performed through a simple set | ||
11 | * of operations that creates the data in a stream type format. | ||
12 | *@author Mike Buland | ||
13 | */ | ||
14 | class XmlDocument | ||
15 | { | ||
16 | public: | ||
17 | /** | ||
18 | * Construct either a blank XmlDocuemnt or construct a document around an | ||
19 | * existing XmlNode. Be careful, once an XmlNode is passed into a document | ||
20 | * the document takes over ownership and will delete it when the XmlDocument | ||
21 | * is deleted. | ||
22 | *@param pRoot The XmlNode to use as the root of this document, or NULL if | ||
23 | * you want to start a new document. | ||
24 | */ | ||
25 | XmlDocument( XmlNode *pRoot=NULL ); | ||
26 | |||
27 | /** | ||
28 | * Destroy all contained nodes. | ||
29 | */ | ||
30 | virtual ~XmlDocument(); | ||
31 | |||
32 | /** | ||
33 | * Add a new node to the document. The new node is appended to the end of | ||
34 | * the current context, i.e. XmlNode, and the new node, provided it isn't | ||
35 | * close as part of this operation, will become the current context. | ||
36 | *@param sName The name of the new node to add. | ||
37 | *@param sContent A content string to be placed inside of the new node. | ||
38 | *@param bClose Set this to true to close the node immediately after adding | ||
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. | ||
41 | */ | ||
42 | void addNode( const Bu::FString &sName ); | ||
43 | |||
44 | /** | ||
45 | * Close the current node context. This will move the current context to | ||
46 | * the parent node of the former current node. If the current node was the | ||
47 | * root then the "completed" flag is set and no more operations are allowed. | ||
48 | */ | ||
49 | void closeNode(); | ||
50 | |||
51 | /** | ||
52 | * Change the content of the current node at the current position between | ||
53 | * nodes. | ||
54 | *@param sContent The new content of the current node. | ||
55 | */ | ||
56 | void setContent( const char *sContent ); | ||
57 | |||
58 | /** | ||
59 | * Add a named property to the current context node. | ||
60 | *@param sName The name of the property to add. | ||
61 | *@param sValue The string value of the property. | ||
62 | */ | ||
63 | void addProperty( const char *sName, const char *sValue ); | ||
64 | |||
65 | /** | ||
66 | * Add a named property to the current context node, converting the | ||
67 | * numerical parameter to text using standrd printf style conversion. | ||
68 | *@param sName The name of the property to add. | ||
69 | *@param nValue The numerical value to add. | ||
70 | */ | ||
71 | void addProperty( const char *sName, const unsigned char nValue ); | ||
72 | |||
73 | /** | ||
74 | * Add a named property to the current context node, converting the | ||
75 | * numerical parameter to text using standrd printf style conversion. | ||
76 | *@param sName The name of the property to add. | ||
77 | *@param nValue The numerical value to add. | ||
78 | */ | ||
79 | void addProperty( const char *sName, const char nValue ); | ||
80 | |||
81 | /** | ||
82 | * Add a named property to the current context node, converting the | ||
83 | * numerical parameter to text using standrd printf style conversion. | ||
84 | *@param sName The name of the property to add. | ||
85 | *@param nValue The numerical value to add. | ||
86 | */ | ||
87 | void addProperty( const char *sName, const unsigned short nValue ); | ||
88 | |||
89 | /** | ||
90 | * Add a named property to the current context node, converting the | ||
91 | * numerical parameter to text using standrd printf style conversion. | ||
92 | *@param sName The name of the property to add. | ||
93 | *@param nValue The numerical value to add. | ||
94 | */ | ||
95 | void addProperty( const char *sName, const short nValue ); | ||
96 | |||
97 | /** | ||
98 | * Add a named property to the current context node, converting the | ||
99 | * numerical parameter to text using standrd printf style conversion. | ||
100 | *@param sName The name of the property to add. | ||
101 | *@param nValue The numerical value to add. | ||
102 | */ | ||
103 | void addProperty( const char *sName, const unsigned long nValue ); | ||
104 | |||
105 | /** | ||
106 | * Add a named property to the current context node, converting the | ||
107 | * numerical parameter to text using standrd printf style conversion. | ||
108 | *@param sName The name of the property to add. | ||
109 | *@param nValue The numerical value to add. | ||
110 | */ | ||
111 | void addProperty( const char *sName, const long nValue ); | ||
112 | |||
113 | /** | ||
114 | * Add a named property to the current context node, converting the | ||
115 | * numerical parameter to text using standrd printf style conversion. | ||
116 | *@param sName The name of the property to add. | ||
117 | *@param nValue The numerical value to add. | ||
118 | */ | ||
119 | void addProperty( const char *sName, const int nValue ); | ||
120 | |||
121 | /** | ||
122 | * Add a named property to the current context node, converting the | ||
123 | * numerical parameter to text using standrd printf style conversion. | ||
124 | *@param sName The name of the property to add. | ||
125 | *@param dValue The numerical value to add. | ||
126 | */ | ||
127 | void addProperty( const char *sName, const double dValue ); | ||
128 | |||
129 | /** | ||
130 | * The XmlDocuemnt is considered completed if the root node has been closed. | ||
131 | * Once an XmlDocument has been completed, you can no longer perform | ||
132 | * operations on it. | ||
133 | *@return True if completed, false if still in progress. | ||
134 | */ | ||
135 | bool isCompleted(); | ||
136 | |||
137 | /** | ||
138 | * Get a pointer to the root object of this XmlDocument. | ||
139 | *@returns A pointer to an internally owned XmlNode. Do not delete this | ||
140 | * XmlNode. | ||
141 | */ | ||
142 | XmlNode *getRoot(); | ||
143 | |||
144 | /** | ||
145 | * Get a pointer to the root object of this XmlDocument, and remove the | ||
146 | * ownership from this object. | ||
147 | *@returns A pointer to an internally owned XmlNode. Do not delete this | ||
148 | * XmlNode. | ||
149 | */ | ||
150 | XmlNode *detatchRoot(); | ||
151 | |||
152 | /** | ||
153 | * Get the current context node, which could be the same as the root node. | ||
154 | *@returns A pointer to an internally owned XmlNode. Do not delete this | ||
155 | * XmlNode. | ||
156 | */ | ||
157 | XmlNode *getCurrent(); | ||
158 | |||
159 | private: | ||
160 | XmlNode *pRoot; /**< The root node. */ | ||
161 | XmlNode *pCurrent; /**< The current node. */ | ||
162 | bool bCompleted; /**< Is it completed? */ | ||
163 | }; | ||
164 | |||
165 | #endif | ||
diff --git a/src/old/xmlnode.cpp b/src/old/xmlnode.cpp new file mode 100644 index 0000000..96d5850 --- /dev/null +++ b/src/old/xmlnode.cpp | |||
@@ -0,0 +1,403 @@ | |||
1 | #include "xmlnode.h" | ||
2 | |||
3 | XmlNode::XmlNode( const Bu::FString &sName, XmlNode *pParent ) : | ||
4 | sName( sName ), | ||
5 | pParent( pParent ) | ||
6 | { | ||
7 | } | ||
8 | |||
9 | XmlNode::~XmlNode() | ||
10 | { | ||
11 | } | ||
12 | /* | ||
13 | void XmlNode::setName( const char *sName ) | ||
14 | { | ||
15 | if( pParent ) | ||
16 | { | ||
17 | if( this->sName.size() == 0 ) | ||
18 | { | ||
19 | // We're not in the hash yet, so add us | ||
20 | this->sName = sName; | ||
21 | pParent->hChildren.insert( this->sName.c_str(), this ); | ||
22 | } | ||
23 | else | ||
24 | { | ||
25 | // Slightly more tricky, delete us, then add us... | ||
26 | pParent->hChildren.del( this->sName.c_str() ); | ||
27 | this->sName = sName; | ||
28 | pParent->hChildren.insert( this->sName.c_str(), this ); | ||
29 | } | ||
30 | } | ||
31 | else | ||
32 | { | ||
33 | // If we have no parent, then just set the name string, we don't need | ||
34 | // to worry about hashing. | ||
35 | this->sName = sName; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | void XmlNode::setContent( const char *sContent, int nIndex ) | ||
40 | { | ||
41 | if( nIndex == -1 ) | ||
42 | { | ||
43 | nIndex = nCurContent; | ||
44 | } | ||
45 | if( nIndex == 0 ) | ||
46 | { | ||
47 | if( this->sPreContent ) | ||
48 | { | ||
49 | delete this->sPreContent; | ||
50 | } | ||
51 | |||
52 | this->sPreContent = new std::string( sContent ); | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | nIndex--; | ||
57 | if( lPostContent[nIndex] ) | ||
58 | { | ||
59 | delete (std::string *)lPostContent[nIndex]; | ||
60 | } | ||
61 | |||
62 | lPostContent.setAt( nIndex, new std::string( sContent ) ); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | const char *XmlNode::getContent( int nIndex ) | ||
67 | { | ||
68 | if( nIndex == 0 ) | ||
69 | { | ||
70 | if( sPreContent ) | ||
71 | { | ||
72 | return sPreContent->c_str(); | ||
73 | } | ||
74 | } | ||
75 | else | ||
76 | { | ||
77 | nIndex--; | ||
78 | if( lPostContent[nIndex] ) | ||
79 | { | ||
80 | return ((std::string *)lPostContent[nIndex])->c_str(); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | return NULL; | ||
85 | }*/ | ||
86 | |||
87 | XmlNode *XmlNode::addChild( const Bu::FString &sName ) | ||
88 | { | ||
89 | return addChild( new XmlNode( sName, this ) ); | ||
90 | } | ||
91 | |||
92 | XmlNode *XmlNode::addChild( XmlNode *pNode ) | ||
93 | { | ||
94 | Child c = { typeNode }; | ||
95 | c.pNode = pNode; | ||
96 | lChildren.append( c ); | ||
97 | pNode->pParent = this; | ||
98 | |||
99 | return pNode; | ||
100 | } | ||
101 | |||
102 | XmlNode *XmlNode::getParent() | ||
103 | { | ||
104 | return pParent; | ||
105 | } | ||
106 | |||
107 | void XmlNode::addProperty( const Bu::FString &sName, const Bu::FString &sValue ) | ||
108 | { | ||
109 | hProperties.insert( sName, sValue ); | ||
110 | } | ||
111 | |||
112 | int XmlNode::getNumProperties() | ||
113 | { | ||
114 | return hProperties.size(); | ||
115 | } | ||
116 | /* | ||
117 | const char *XmlNode::getPropertyName( int nIndex ) | ||
118 | { | ||
119 | std::string *tmp = ((std::string *)lPropNames[nIndex]); | ||
120 | if( tmp == NULL ) | ||
121 | return NULL; | ||
122 | return tmp->c_str(); | ||
123 | } | ||
124 | |||
125 | const char *XmlNode::getProperty( int nIndex ) | ||
126 | { | ||
127 | std::string *tmp = ((std::string *)lPropValues[nIndex]); | ||
128 | if( tmp == NULL ) | ||
129 | return NULL; | ||
130 | return tmp->c_str(); | ||
131 | } | ||
132 | */ | ||
133 | Bu::FString XmlNode::getProperty( const Bu::FString &sName ) | ||
134 | { | ||
135 | return hProperties[sName]; | ||
136 | } | ||
137 | /* | ||
138 | void XmlNode::deleteProperty( int nIndex ) | ||
139 | { | ||
140 | hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); | ||
141 | |||
142 | delete (std::string *)lPropNames[nIndex]; | ||
143 | delete (std::string *)lPropValues[nIndex]; | ||
144 | |||
145 | lPropNames.deleteAt( nIndex ); | ||
146 | lPropValues.deleteAt( nIndex ); | ||
147 | } | ||
148 | |||
149 | bool XmlNode::hasChildren() | ||
150 | { | ||
151 | return hChildren.getSize()>0; | ||
152 | }*/ | ||
153 | |||
154 | int XmlNode::getNumChildren() | ||
155 | { | ||
156 | return lChildren.getSize(); | ||
157 | } | ||
158 | /* | ||
159 | XmlNode *XmlNode::getChild( int nIndex ) | ||
160 | { | ||
161 | return (XmlNode *)lChildren[nIndex]; | ||
162 | } | ||
163 | */ | ||
164 | XmlNode *XmlNode::getChild( const Bu::FString &sName, int nSkip ) | ||
165 | { | ||
166 | if( !hChildren.has( sName ) ) | ||
167 | return NULL; | ||
168 | |||
169 | Bu::List<XmlNode *>::iterator i = hChildren[sName]->begin(); | ||
170 | return *i; | ||
171 | } | ||
172 | |||
173 | Bu::FString XmlNode::getName() | ||
174 | { | ||
175 | return sName; | ||
176 | } | ||
177 | /* | ||
178 | void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) | ||
179 | { | ||
180 | XmlNode *xRet = detatchNode( nIndex, sReplacementText ); | ||
181 | |||
182 | if( xRet != NULL ) | ||
183 | { | ||
184 | delete xRet; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | XmlNode *XmlNode::detatchNode( int nIndex, const char *sReplacementText ) | ||
189 | { | ||
190 | if( nIndex < 0 || nIndex >= lChildren.getSize() ) | ||
191 | return NULL; | ||
192 | |||
193 | // The real trick when deleteing a node isn't actually deleting it, it's | ||
194 | // reforming the content around the node that's now missing...hmmm... | ||
195 | |||
196 | if( nIndex == 0 ) | ||
197 | { | ||
198 | // If the index is zero we have to deal with the pre-content | ||
199 | if( sReplacementText ) | ||
200 | { | ||
201 | if( sPreContent == NULL ) | ||
202 | { | ||
203 | sPreContent = new std::string( sReplacementText ); | ||
204 | } | ||
205 | else | ||
206 | { | ||
207 | *sPreContent += sReplacementText; | ||
208 | } | ||
209 | } | ||
210 | if( lPostContent.getSize() > 0 ) | ||
211 | { | ||
212 | if( lPostContent[0] != NULL ) | ||
213 | { | ||
214 | if( sPreContent == NULL ) | ||
215 | { | ||
216 | sPreContent = new std::string( | ||
217 | ((std::string *)lPostContent[0])->c_str() | ||
218 | ); | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | *sPreContent += | ||
223 | ((std::string *)lPostContent[0])->c_str(); | ||
224 | } | ||
225 | } | ||
226 | delete (std::string *)lPostContent[0]; | ||
227 | lPostContent.deleteAt( 0 ); | ||
228 | } | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | int nCont = nIndex-1; | ||
233 | // If it's above zero we deal with the post-content only | ||
234 | if( sReplacementText ) | ||
235 | { | ||
236 | if( lPostContent[nCont] == NULL ) | ||
237 | { | ||
238 | lPostContent.setAt( nCont, new std::string( sReplacementText ) ); | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | *((std::string *)lPostContent[nCont]) += sReplacementText; | ||
243 | } | ||
244 | } | ||
245 | if( lPostContent.getSize() > nIndex ) | ||
246 | { | ||
247 | if( lPostContent[nIndex] != NULL ) | ||
248 | { | ||
249 | if( lPostContent[nCont] == NULL ) | ||
250 | { | ||
251 | lPostContent.setAt( nCont, new std::string( | ||
252 | ((std::string *)lPostContent[nIndex])->c_str() | ||
253 | ) ); | ||
254 | } | ||
255 | else | ||
256 | { | ||
257 | *((std::string *)lPostContent[nCont]) += | ||
258 | ((std::string *)lPostContent[nIndex])->c_str(); | ||
259 | } | ||
260 | } | ||
261 | delete (std::string *)lPostContent[nIndex]; | ||
262 | lPostContent.deleteAt( nIndex ); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | XmlNode *xRet = (XmlNode *)lChildren[nIndex]; | ||
267 | hChildren.del( ((XmlNode *)lChildren[nIndex])->getName() ); | ||
268 | lChildren.deleteAt( nIndex ); | ||
269 | |||
270 | return xRet; | ||
271 | } | ||
272 | |||
273 | void XmlNode::replaceNode( int nIndex, XmlNode *pNewNode ) | ||
274 | { | ||
275 | if( nIndex < 0 || nIndex >= lChildren.getSize() ) | ||
276 | return; //TODO: throw an exception | ||
277 | |||
278 | delete (XmlNode *)lChildren[nIndex]; | ||
279 | lChildren.setAt( nIndex, pNewNode ); | ||
280 | pNewNode->pParent = this; | ||
281 | } | ||
282 | |||
283 | XmlNode *XmlNode::getCopy() | ||
284 | { | ||
285 | XmlNode *pNew = new XmlNode(); | ||
286 | |||
287 | pNew->sName = sName; | ||
288 | if( sPreContent ) | ||
289 | { | ||
290 | pNew->sPreContent = new std::string( sPreContent->c_str() ); | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | pNew->sPreContent = NULL; | ||
295 | } | ||
296 | pNew->nCurContent = 0; | ||
297 | |||
298 | int nSize = lPostContent.getSize(); | ||
299 | pNew->lPostContent.setSize( nSize ); | ||
300 | for( int j = 0; j < nSize; j++ ) | ||
301 | { | ||
302 | if( lPostContent[j] ) | ||
303 | { | ||
304 | pNew->lPostContent.setAt( | ||
305 | j, new std::string( | ||
306 | ((std::string *)lPostContent[j])->c_str() | ||
307 | ) | ||
308 | ); | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | pNew->lPostContent.setAt( j, NULL ); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | nSize = lChildren.getSize(); | ||
317 | pNew->lChildren.setSize( nSize ); | ||
318 | for( int j = 0; j < nSize; j++ ) | ||
319 | { | ||
320 | XmlNode *pChild = ((XmlNode *)lChildren[j])->getCopy(); | ||
321 | pNew->lChildren.setAt( j, pChild ); | ||
322 | pChild->pParent = pNew; | ||
323 | pNew->hChildren.insert( pChild->getName(), pChild ); | ||
324 | } | ||
325 | |||
326 | nSize = lPropNames.getSize(); | ||
327 | pNew->lPropNames.setSize( nSize ); | ||
328 | pNew->lPropValues.setSize( nSize ); | ||
329 | for( int j = 0; j < nSize; j++ ) | ||
330 | { | ||
331 | std::string *pProp = new std::string( ((std::string *)lPropNames[j])->c_str() ); | ||
332 | std::string *pVal = new std::string( ((std::string *)lPropValues[j])->c_str() ); | ||
333 | pNew->lPropNames.setAt( j, pProp ); | ||
334 | pNew->lPropValues.setAt( j, pVal ); | ||
335 | pNew->hProperties.insert( pProp->c_str(), pVal->c_str() ); | ||
336 | pNew->nCurContent++; | ||
337 | } | ||
338 | |||
339 | return pNew; | ||
340 | } | ||
341 | |||
342 | void XmlNode::deleteNodeKeepChildren( int nIndex ) | ||
343 | { | ||
344 | // This is a tricky one...we need to do some patching to keep things all | ||
345 | // even... | ||
346 | XmlNode *xRet = (XmlNode *)lChildren[nIndex]; | ||
347 | |||
348 | if( xRet == NULL ) | ||
349 | { | ||
350 | return; | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | if( getContent( nIndex ) ) | ||
355 | { | ||
356 | std::string sBuf( getContent( nIndex ) ); | ||
357 | sBuf += xRet->getContent( 0 ); | ||
358 | setContent( sBuf.c_str(), nIndex ); | ||
359 | } | ||
360 | else | ||
361 | { | ||
362 | setContent( xRet->getContent( 0 ), nIndex ); | ||
363 | } | ||
364 | |||
365 | int nSize = xRet->lChildren.getSize(); | ||
366 | for( int j = 0; j < nSize; j++ ) | ||
367 | { | ||
368 | XmlNode *pCopy = ((XmlNode *)xRet->lChildren[j])->getCopy(); | ||
369 | pCopy->pParent = this; | ||
370 | lChildren.insertBefore( pCopy, nIndex+j ); | ||
371 | |||
372 | if( xRet->lPostContent[j] ) | ||
373 | { | ||
374 | lPostContent.insertBefore( | ||
375 | new std::string( ((std::string *)xRet->lPostContent[j])->c_str() ), | ||
376 | nIndex+j | ||
377 | ); | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | lPostContent.insertBefore( NULL, nIndex+j ); | ||
382 | } | ||
383 | } | ||
384 | |||
385 | if( getContent( nIndex+nSize ) ) | ||
386 | { | ||
387 | //SString sBuf( getContent( nIndex+nSize ) ); | ||
388 | //sBuf.catfrom( xRet->getContent( nSize ) ); | ||
389 | //setContent( sBuf, nIndex+nSize ); | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | setContent( xRet->getContent( nSize ), nIndex+nSize ); | ||
394 | } | ||
395 | |||
396 | deleteNode( nIndex+nSize ); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) | ||
401 | { | ||
402 | } | ||
403 | */ | ||
diff --git a/src/old/xmlnode.h b/src/old/xmlnode.h new file mode 100644 index 0000000..c895cd8 --- /dev/null +++ b/src/old/xmlnode.h | |||
@@ -0,0 +1,207 @@ | |||
1 | #ifndef XMLNODE | ||
2 | #define XMLNODE | ||
3 | |||
4 | #include <iostream> | ||
5 | #include "bu/list.h" | ||
6 | #include "bu/hash.h" | ||
7 | #include "bu/fstring.h" | ||
8 | |||
9 | /** | ||
10 | * Maintains all data pertient to an XML node, including sub-nodes and content. | ||
11 | * All child nodes can be accessed through index and through name via a hash | ||
12 | * table. This makes it very easy to gain simple and fast access to all of | ||
13 | * your data. For most applications, the memory footprint is also rather | ||
14 | * small. While XmlNode objects can be used directly to create XML structures | ||
15 | * it is highly reccomended that all operations be performed through the | ||
16 | * XmlDocument class. | ||
17 | *@author Mike Buland | ||
18 | */ | ||
19 | class XmlNode | ||
20 | { | ||
21 | public: | ||
22 | /** | ||
23 | * Construct a new XmlNode. | ||
24 | *@param sName The name of the node. | ||
25 | *@param pParent The parent node. | ||
26 | *@param sContent The initial content string. | ||
27 | */ | ||
28 | XmlNode( | ||
29 | const Bu::FString &sName, | ||
30 | XmlNode *pParent=NULL | ||
31 | ); | ||
32 | |||
33 | /** | ||
34 | * Delete the node and cleanup all memory. | ||
35 | */ | ||
36 | virtual ~XmlNode(); | ||
37 | |||
38 | /** | ||
39 | * Change the name of the node. | ||
40 | *@param sName The new name of the node. | ||
41 | */ | ||
42 | //void setName( const char *sName ); | ||
43 | |||
44 | /** | ||
45 | * Construct a new node and add it as a child to this node, also return a | ||
46 | * pointer to the newly constructed node. | ||
47 | *@param sName The name of the new node. | ||
48 | *@param sContent The initial content of the new node. | ||
49 | *@returns A pointer to the newly created child node. | ||
50 | */ | ||
51 | XmlNode *addChild( const Bu::FString &sName ); | ||
52 | |||
53 | /** | ||
54 | * Add an already created XmlNode as a child to this node. The new child | ||
55 | * XmlNode's parent will be changed appropriately and the parent XmlNode | ||
56 | * will take ownership of the child. | ||
57 | *@param pChild The child XmlNode to add to this XmlNode. | ||
58 | *@returns A pointer to the child node that was just added. | ||
59 | */ | ||
60 | XmlNode *addChild( XmlNode *pChild ); | ||
61 | |||
62 | /** | ||
63 | * Add a new property to the XmlNode. Properties are name/value pairs. | ||
64 | *@param sName The name of the property. Specifying a name that's already | ||
65 | * in use will overwrite that property. | ||
66 | *@param sValue The textual value of the property. | ||
67 | */ | ||
68 | void addProperty( const Bu::FString &sName, const Bu::FString &sValue ); | ||
69 | |||
70 | /** | ||
71 | * Get a pointer to the parent node, if any. | ||
72 | *@returns A pointer to the node's parent, or NULL if there isn't one. | ||
73 | */ | ||
74 | XmlNode *getParent(); | ||
75 | |||
76 | /** | ||
77 | * Tells you if this node has children. | ||
78 | *@returns True if this node has at least one child, false otherwise. | ||
79 | */ | ||
80 | bool hasChildren(); | ||
81 | |||
82 | /** | ||
83 | * Tells you how many children this node has. | ||
84 | *@returns The number of children this node has. | ||
85 | */ | ||
86 | int getNumChildren(); | ||
87 | |||
88 | /** | ||
89 | * Get a child with the specified name, and possibly skip value. For an | ||
90 | * explination of skip values see the HashTable. | ||
91 | *@param sName The name of the child to find. | ||
92 | *@param nSkip The number of nodes with that name to skip. | ||
93 | *@returns A pointer to the child, or NULL if no child with that name was | ||
94 | * found. | ||
95 | */ | ||
96 | XmlNode *getChild( const Bu::FString &sName, int nSkip=0 ); | ||
97 | |||
98 | /** | ||
99 | * Get a pointer to the name of this node. Do not change this, use setName | ||
100 | * instead. | ||
101 | *@returns A pointer to the name of this node. | ||
102 | */ | ||
103 | Bu::FString getName(); | ||
104 | |||
105 | /** | ||
106 | * Set the content of this node, optionally at a specific index. Using the | ||
107 | * default of -1 will set the content after the last added node. | ||
108 | *@param sContent The content string to use. | ||
109 | *@param nIndex The index of the content. | ||
110 | */ | ||
111 | //void setContent( const char *sContent, int nIndex=-1 ); | ||
112 | |||
113 | /** | ||
114 | * Get the number of properties in this node. | ||
115 | *@returns The number of properties in this node. | ||
116 | */ | ||
117 | int getNumProperties(); | ||
118 | |||
119 | /** | ||
120 | * Get a propery's value by name. | ||
121 | *@param sName The name of the property to examine. | ||
122 | *@returns A pointer to the value of the property specified, or NULL if none | ||
123 | * found. | ||
124 | */ | ||
125 | Bu::FString getProperty( const Bu::FString &sName ); | ||
126 | |||
127 | /** | ||
128 | * Delete a child node, possibly replacing it with some text. This actually | ||
129 | * fixes all content strings around the newly deleted child node. | ||
130 | *@param nIndex The index of the node to delete. | ||
131 | *@param sReplacementText The optional text to replace the node with. | ||
132 | *@returns True of the node was found, and deleted, false if it wasn't | ||
133 | * found. | ||
134 | */ | ||
135 | //void deleteNode( int nIndex, const char *sReplacementText = NULL ); | ||
136 | |||
137 | /** | ||
138 | * Delete a given node, but move all of it's children and content up to | ||
139 | * replace the deleted node. All of the content of the child node is | ||
140 | * spliced seamlessly into place with the parent node's content. | ||
141 | *@param nIndex The node to delete. | ||
142 | *@returns True if the node was found and deleted, false if it wasn't. | ||
143 | */ | ||
144 | //void deleteNodeKeepChildren( int nIndex ); | ||
145 | |||
146 | /** | ||
147 | * Detatch a given child node from this node. This effectively works just | ||
148 | * like a deleteNode, except that instead of deleting the node it is removed | ||
149 | * and returned, and all ownership is given up. | ||
150 | *@param nIndex The index of the node to detatch. | ||
151 | *@param sReplacementText The optional text to replace the detatched node | ||
152 | * with. | ||
153 | *@returns A pointer to the newly detatched node, which then passes | ||
154 | * ownership to the caller. | ||
155 | */ | ||
156 | //XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); | ||
157 | |||
158 | /** | ||
159 | * Replace a given node with a different node that is not currently owned by | ||
160 | * this XmlNode or any ancestor. | ||
161 | *@param nIndex The index of the node to replace. | ||
162 | *@param pNewNode The new node to replace the old node with. | ||
163 | *@returns True if the node was found and replaced, false if it wasn't. | ||
164 | */ | ||
165 | //void replaceNode( int nIndex, XmlNode *pNewNode ); | ||
166 | |||
167 | /** | ||
168 | * Replace a given node with the children and content of a given node. | ||
169 | *@param nIndex The index of the node to replace. | ||
170 | *@param pNewNode The node that contains the children and content that will | ||
171 | * replace the node specified by nIndex. | ||
172 | *@returns True if the node was found and replaced, false if it wasn't. | ||
173 | */ | ||
174 | //void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); | ||
175 | |||
176 | /** | ||
177 | * Get a copy of this node and all children. getCopy is recursive, so | ||
178 | * beware copying large trees of xml. | ||
179 | *@returns A newly created copy of this node and all of it's children. | ||
180 | */ | ||
181 | //XmlNode *getCopy(); | ||
182 | |||
183 | enum ChildType | ||
184 | { | ||
185 | typeNode, | ||
186 | typeContent | ||
187 | }; | ||
188 | |||
189 | private: | ||
190 | typedef struct | ||
191 | { | ||
192 | uint8_t nType; | ||
193 | union { | ||
194 | XmlNode *pNode; | ||
195 | Bu::FString *pContent; | ||
196 | }; | ||
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. */ | ||
202 | XmlNode *pParent; /**< A pointer to the parent of this node. */ | ||
203 | int nCurContent; /**< The current content we're on, for using the -1 on | ||
204 | setContent. */ | ||
205 | }; | ||
206 | |||
207 | #endif | ||
diff --git a/src/old/xmlreader.cpp b/src/old/xmlreader.cpp new file mode 100644 index 0000000..38cad5f --- /dev/null +++ b/src/old/xmlreader.cpp | |||
@@ -0,0 +1,604 @@ | |||
1 | #include "bu/xmlreader.h" | ||
2 | #include "bu/exceptions.h" | ||
3 | #include <string.h> | ||
4 | |||
5 | XmlReader::XmlReader( Bu::Stream &sIn, bool bStrip ) : | ||
6 | sIn( sIn ), | ||
7 | bStrip( bStrip ) | ||
8 | { | ||
9 | buildDoc(); | ||
10 | } | ||
11 | |||
12 | XmlReader::~XmlReader() | ||
13 | { | ||
14 | } | ||
15 | |||
16 | char XmlReader::getChar( int nIndex ) | ||
17 | { | ||
18 | if( sBuf.getSize() <= nIndex ) | ||
19 | { | ||
20 | int nInc = nIndex-sBuf.getSize()+1; | ||
21 | char *buf = new char[nInc]; | ||
22 | sIn.read( buf, nInc ); | ||
23 | sBuf.append( buf, nInc ); | ||
24 | delete[] buf; | ||
25 | } | ||
26 | |||
27 | return sBuf[nIndex]; | ||
28 | } | ||
29 | |||
30 | void XmlReader::usedChar( int nAmnt ) | ||
31 | { | ||
32 | if( nAmnt >= sBuf.getSize() ) | ||
33 | { | ||
34 | sBuf.clear(); | ||
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 | } | ||
43 | |||
44 | void XmlReader::addEntity( const Bu::FString &name, const Bu::FString &value ) | ||
45 | { | ||
46 | htEntity[name] = value; | ||
47 | } | ||
48 | |||
49 | #define gcall( x ) if( x == false ) return false; | ||
50 | |||
51 | bool XmlReader::isws( char chr ) | ||
52 | { | ||
53 | return ( chr == ' ' || chr == '\t' || chr == '\n' || chr == '\r' ); | ||
54 | } | ||
55 | |||
56 | bool XmlReader::ws() | ||
57 | { | ||
58 | while( true ) | ||
59 | { | ||
60 | char chr = getChar(); | ||
61 | if( isws( chr ) ) | ||
62 | { | ||
63 | usedChar(); | ||
64 | } | ||
65 | else | ||
66 | { | ||
67 | return true; | ||
68 | } | ||
69 | } | ||
70 | return true; | ||
71 | } | ||
72 | |||
73 | bool XmlReader::buildDoc() | ||
74 | { | ||
75 | // take care of initial whitespace | ||
76 | gcall( ws() ); | ||
77 | textDecl(); | ||
78 | entity(); | ||
79 | addEntity("gt", ">"); | ||
80 | addEntity("lt", "<"); | ||
81 | addEntity("amp", "&"); | ||
82 | addEntity("apos", "\'"); | ||
83 | addEntity("quot", "\""); | ||
84 | gcall( node() ); | ||
85 | |||
86 | return true; | ||
87 | } | ||
88 | |||
89 | void XmlReader::textDecl() | ||
90 | { | ||
91 | if( getChar() == '<' && getChar( 1 ) == '?' ) | ||
92 | { | ||
93 | usedChar( 2 ); | ||
94 | for(;;) | ||
95 | { | ||
96 | if( getChar() == '?' ) | ||
97 | { | ||
98 | if( getChar( 1 ) == '>' ) | ||
99 | { | ||
100 | usedChar( 2 ); | ||
101 | return; | ||
102 | } | ||
103 | } | ||
104 | usedChar(); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void XmlReader::entity() | ||
110 | { | ||
111 | for(;;) | ||
112 | { | ||
113 | ws(); | ||
114 | |||
115 | if( getChar() == '<' && getChar( 1 ) == '!' ) | ||
116 | { | ||
117 | usedChar( 2 ); | ||
118 | ws(); | ||
119 | Bu::FString buf; | ||
120 | for(;;) | ||
121 | { | ||
122 | char chr = getChar(); | ||
123 | usedChar(); | ||
124 | if( isws( chr ) ) break; | ||
125 | buf += chr; | ||
126 | } | ||
127 | |||
128 | if( strcmp( buf.c_str(), "ENTITY") == 0 ) | ||
129 | { | ||
130 | ws(); | ||
131 | Bu::FString name; | ||
132 | for(;;) | ||
133 | { | ||
134 | char chr = getChar(); | ||
135 | usedChar(); | ||
136 | if( isws( chr ) ) break; | ||
137 | name += chr; | ||
138 | } | ||
139 | ws(); | ||
140 | char quot = getChar(); | ||
141 | usedChar(); | ||
142 | if( quot != '\'' && quot != '\"' ) | ||
143 | { | ||
144 | throw Bu::XmlException( | ||
145 | "Only quoted entity values are supported." | ||
146 | ); | ||
147 | } | ||
148 | Bu::FString value; | ||
149 | for(;;) | ||
150 | { | ||
151 | char chr = getChar(); | ||
152 | usedChar(); | ||
153 | if( chr == '&' ) | ||
154 | { | ||
155 | Bu::FString tmp = getEscape(); | ||
156 | value += tmp; | ||
157 | } | ||
158 | else if( chr == quot ) | ||
159 | { | ||
160 | break; | ||
161 | } | ||
162 | else | ||
163 | { | ||
164 | value += chr; | ||
165 | } | ||
166 | } | ||
167 | ws(); | ||
168 | if( getChar() == '>' ) | ||
169 | { | ||
170 | usedChar(); | ||
171 | |||
172 | addEntity( name.c_str(), value.c_str() ); | ||
173 | } | ||
174 | else | ||
175 | { | ||
176 | throw Bu::XmlException( | ||
177 | "Malformed ENTITY: unexpected '%c' found.", | ||
178 | getChar() | ||
179 | ); | ||
180 | } | ||
181 | } | ||
182 | else | ||
183 | { | ||
184 | throw Bu::XmlException( | ||
185 | "Unsupported header symbol: %s", | ||
186 | buf.c_str() | ||
187 | ); | ||
188 | } | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | return; | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | bool XmlReader::node() | ||
198 | { | ||
199 | gcall( startNode() ) | ||
200 | |||
201 | // At this point, we are closing the startNode | ||
202 | char chr = getChar(); | ||
203 | if( chr == '>' ) | ||
204 | { | ||
205 | usedChar(); | ||
206 | |||
207 | // Now we process the guts of the node. | ||
208 | gcall( content() ); | ||
209 | } | ||
210 | else if( chr == '/' ) | ||
211 | { | ||
212 | // This is the tricky one, one more validation, then we close the node. | ||
213 | usedChar(); | ||
214 | if( getChar() == '>' ) | ||
215 | { | ||
216 | closeNode(); | ||
217 | usedChar(); | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | throw Bu::XmlException("Close node in singleNode malformed!"); | ||
222 | } | ||
223 | } | ||
224 | else | ||
225 | { | ||
226 | throw Bu::XmlException("Close node expected, but not found."); | ||
227 | return false; | ||
228 | } | ||
229 | |||
230 | return true; | ||
231 | } | ||
232 | |||
233 | bool XmlReader::startNode() | ||
234 | { | ||
235 | if( getChar() == '<' ) | ||
236 | { | ||
237 | usedChar(); | ||
238 | |||
239 | if( getChar() == '/' ) | ||
240 | { | ||
241 | // Heh, it's actually a close node, go figure | ||
242 | Bu::FString sName; | ||
243 | usedChar(); | ||
244 | gcall( ws() ); | ||
245 | |||
246 | while( true ) | ||
247 | { | ||
248 | char chr = getChar(); | ||
249 | if( isws( chr ) || chr == '>' ) | ||
250 | { | ||
251 | // Here we actually compare the name we got to the name | ||
252 | // we already set, they have to match exactly. | ||
253 | if( getCurrent()->getName() == sName ) | ||
254 | { | ||
255 | closeNode(); | ||
256 | break; | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | throw Bu::XmlException("Got a mismatched node close tag."); | ||
261 | } | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | sName += chr; | ||
266 | usedChar(); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | gcall( ws() ); | ||
271 | if( getChar() == '>' ) | ||
272 | { | ||
273 | // Everything is cool. | ||
274 | usedChar(); | ||
275 | } | ||
276 | else | ||
277 | { | ||
278 | throw Bu::XmlException("Got extra junk data instead of node close tag."); | ||
279 | } | ||
280 | } | ||
281 | else | ||
282 | { | ||
283 | // We're good, format is consistant | ||
284 | //addNode(); | ||
285 | |||
286 | // Skip extra whitespace | ||
287 | gcall( ws() ); | ||
288 | gcall( name() ); | ||
289 | gcall( ws() ); | ||
290 | gcall( paramlist() ); | ||
291 | gcall( ws() ); | ||
292 | } | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | throw Bu::XmlException("Expected to find node opening char, '<'."); | ||
297 | } | ||
298 | |||
299 | return true; | ||
300 | } | ||
301 | |||
302 | bool XmlReader::name() | ||
303 | { | ||
304 | Bu::FString sName; | ||
305 | |||
306 | while( true ) | ||
307 | { | ||
308 | char chr = getChar(); | ||
309 | if( isws( chr ) || chr == '>' || chr == '/' ) | ||
310 | { | ||
311 | addNode( sName ); | ||
312 | return true; | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | sName += chr; | ||
317 | usedChar(); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | return true; | ||
322 | } | ||
323 | |||
324 | bool XmlReader::paramlist() | ||
325 | { | ||
326 | while( true ) | ||
327 | { | ||
328 | char chr = getChar(); | ||
329 | if( chr == '/' || chr == '>' ) | ||
330 | { | ||
331 | return true; | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | gcall( param() ); | ||
336 | gcall( ws() ); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | return true; | ||
341 | } | ||
342 | |||
343 | Bu::FString XmlReader::getEscape() | ||
344 | { | ||
345 | if( getChar( 1 ) == '#' ) | ||
346 | { | ||
347 | // If the entity starts with a # it's a character escape code | ||
348 | int base = 10; | ||
349 | usedChar( 2 ); | ||
350 | if( getChar() == 'x' ) | ||
351 | { | ||
352 | base = 16; | ||
353 | usedChar(); | ||
354 | } | ||
355 | char buf[4]; | ||
356 | int j = 0; | ||
357 | for( j = 0; getChar() != ';'; j++ ) | ||
358 | { | ||
359 | buf[j] = getChar(); | ||
360 | usedChar(); | ||
361 | } | ||
362 | usedChar(); | ||
363 | buf[j] = '\0'; | ||
364 | buf[0] = (char)strtol( buf, (char **)NULL, base ); | ||
365 | buf[1] = '\0'; | ||
366 | |||
367 | return buf; | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | // ...otherwise replace with the appropriate string... | ||
372 | Bu::FString buf; | ||
373 | usedChar(); | ||
374 | for(;;) | ||
375 | { | ||
376 | char cbuf = getChar(); | ||
377 | usedChar(); | ||
378 | if( cbuf == ';' ) break; | ||
379 | buf += cbuf; | ||
380 | } | ||
381 | |||
382 | return htEntity[buf]; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | bool XmlReader::param() | ||
387 | { | ||
388 | Bu::FString sName; | ||
389 | Bu::FString sValue; | ||
390 | |||
391 | while( true ) | ||
392 | { | ||
393 | char chr = getChar(); | ||
394 | if( isws( chr ) || chr == '=' ) | ||
395 | { | ||
396 | break; | ||
397 | } | ||
398 | else | ||
399 | { | ||
400 | sName.append( chr ); | ||
401 | usedChar(); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | gcall( ws() ); | ||
406 | |||
407 | if( getChar() == '=' ) | ||
408 | { | ||
409 | usedChar(); | ||
410 | |||
411 | gcall( ws() ); | ||
412 | |||
413 | char chr = getChar(); | ||
414 | if( chr == '"' ) | ||
415 | { | ||
416 | // Better quoted rhs | ||
417 | usedChar(); | ||
418 | |||
419 | while( true ) | ||
420 | { | ||
421 | chr = getChar(); | ||
422 | if( chr == '"' ) | ||
423 | { | ||
424 | usedChar(); | ||
425 | addProperty( sName.getStr(), sValue.getStr() ); | ||
426 | return true; | ||
427 | } | ||
428 | else | ||
429 | { | ||
430 | if( chr == '&' ) | ||
431 | { | ||
432 | sValue += getEscape(); | ||
433 | } | ||
434 | else | ||
435 | { | ||
436 | sValue += chr; | ||
437 | usedChar(); | ||
438 | } | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | else | ||
443 | { | ||
444 | // Simple one-word rhs | ||
445 | while( true ) | ||
446 | { | ||
447 | chr = getChar(); | ||
448 | if( isws( chr ) || chr == '/' || chr == '>' ) | ||
449 | { | ||
450 | addProperty( sName.getStr(), sValue.getStr() ); | ||
451 | return true; | ||
452 | } | ||
453 | else | ||
454 | { | ||
455 | if( chr == '&' ) | ||
456 | { | ||
457 | sValue += getEscape(); | ||
458 | } | ||
459 | else | ||
460 | { | ||
461 | sValue += chr; | ||
462 | usedChar(); | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | else | ||
469 | { | ||
470 | throw Bu::XmlException("Expected an equals to seperate the params."); | ||
471 | return false; | ||
472 | } | ||
473 | |||
474 | return true; | ||
475 | } | ||
476 | |||
477 | bool XmlReader::content() | ||
478 | { | ||
479 | Bu::FString sContent; | ||
480 | |||
481 | if( bStrip ) gcall( ws() ); | ||
482 | |||
483 | while( true ) | ||
484 | { | ||
485 | char chr = getChar(); | ||
486 | if( chr == '<' ) | ||
487 | { | ||
488 | if( getChar(1) == '/' ) | ||
489 | { | ||
490 | if( sContent.getSize() > 0 ) | ||
491 | { | ||
492 | if( bStrip ) | ||
493 | { | ||
494 | int j; | ||
495 | for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); | ||
496 | sContent[j+1] = '\0'; | ||
497 | } | ||
498 | setContent( sContent.getStr() ); | ||
499 | } | ||
500 | usedChar( 2 ); | ||
501 | gcall( ws() ); | ||
502 | Bu::FString sName; | ||
503 | while( true ) | ||
504 | { | ||
505 | chr = getChar(); | ||
506 | if( isws( chr ) || chr == '>' ) | ||
507 | { | ||
508 | if( !strcasecmp( getCurrent()->getName().getStr(), sName.getStr() ) ) | ||
509 | { | ||
510 | closeNode(); | ||
511 | break; | ||
512 | } | ||
513 | else | ||
514 | { | ||
515 | throw Bu::XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName().getStr(), sName.getStr() ); | ||
516 | } | ||
517 | } | ||
518 | else | ||
519 | { | ||
520 | sName += chr; | ||
521 | usedChar(); | ||
522 | } | ||
523 | } | ||
524 | gcall( ws() ); | ||
525 | if( getChar() == '>' ) | ||
526 | { | ||
527 | usedChar(); | ||
528 | return true; | ||
529 | } | ||
530 | else | ||
531 | { | ||
532 | throw Bu::XmlException("Malformed close tag."); | ||
533 | } | ||
534 | } | ||
535 | else if( getChar(1) == '!' ) | ||
536 | { | ||
537 | // We know it's a comment, let's see if it's proper | ||
538 | if( getChar(2) != '-' || | ||
539 | getChar(3) != '-' ) | ||
540 | { | ||
541 | // Not a valid XML comment | ||
542 | throw Bu::XmlException("Malformed comment start tag found."); | ||
543 | } | ||
544 | |||
545 | usedChar( 4 ); | ||
546 | |||
547 | // Now burn text until we find the close tag | ||
548 | for(;;) | ||
549 | { | ||
550 | if( getChar() == '-' ) | ||
551 | { | ||
552 | if( getChar( 1 ) == '-' ) | ||
553 | { | ||
554 | // The next one has to be a '>' now | ||
555 | if( getChar( 2 ) != '>' ) | ||
556 | { | ||
557 | throw Bu::XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); | ||
558 | } | ||
559 | usedChar( 3 ); | ||
560 | break; | ||
561 | } | ||
562 | else | ||
563 | { | ||
564 | // Found a dash followed by a non dash, that's ok... | ||
565 | usedChar( 2 ); | ||
566 | } | ||
567 | } | ||
568 | else | ||
569 | { | ||
570 | // Burn comment chars | ||
571 | usedChar(); | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | else | ||
576 | { | ||
577 | if( sContent.getSize() > 0 ) | ||
578 | { | ||
579 | if( bStrip ) | ||
580 | { | ||
581 | int j; | ||
582 | for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); | ||
583 | sContent[j+1] = '\0'; | ||
584 | } | ||
585 | setContent( sContent.getStr() ); | ||
586 | sContent.clear(); | ||
587 | } | ||
588 | gcall( node() ); | ||
589 | } | ||
590 | |||
591 | if( bStrip ) gcall( ws() ); | ||
592 | } | ||
593 | else if( chr == '&' ) | ||
594 | { | ||
595 | sContent += getEscape(); | ||
596 | } | ||
597 | else | ||
598 | { | ||
599 | sContent += chr; | ||
600 | usedChar(); | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | |||
diff --git a/src/old/xmlreader.h b/src/old/xmlreader.h new file mode 100644 index 0000000..7c85ddb --- /dev/null +++ b/src/old/xmlreader.h | |||
@@ -0,0 +1,144 @@ | |||
1 | #ifndef XMLREADER | ||
2 | #define XMLREADER | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include "bu/xmldocument.h" | ||
6 | #include "bu/hash.h" | ||
7 | #include "bu/fstring.h" | ||
8 | #include "bu/stream.h" | ||
9 | |||
10 | /** | ||
11 | * Takes care of reading in xml formatted data from a file. This could/should | ||
12 | * be made more arbitrary in the future so that we can read the data from any | ||
13 | * source. This is actually made quite simple already since all data read in | ||
14 | * is handled by one single helper function and then palced into a FlexBuf for | ||
15 | * easy access by the other functions. The FlexBuf also allows for block | ||
16 | * reading from disk, which improves speed by a noticable amount. | ||
17 | * <br> | ||
18 | * There are also some extra features implemented that allow you to break the | ||
19 | * standard XML reader specs and eliminate leading and trailing whitespace in | ||
20 | * all read content. This is useful in situations where you allow additional | ||
21 | * whitespace in the files to make them easily human readable. The resturned | ||
22 | * content will be NULL in sitautions where all content between nodes was | ||
23 | * stripped. | ||
24 | *@author Mike Buland | ||
25 | */ | ||
26 | class XmlReader : public XmlDocument | ||
27 | { | ||
28 | public: | ||
29 | /** | ||
30 | * Create a standard XmlReader. The optional parameter bStrip allows you to | ||
31 | * create a reader that will strip out all leading and trailing whitespace | ||
32 | * in content, a-la html. | ||
33 | *@param bStrip Strip out leading and trailing whitespace? | ||
34 | */ | ||
35 | XmlReader( Bu::Stream &sIn, bool bStrip=false ); | ||
36 | |||
37 | /** | ||
38 | * Destroy this XmlReader. | ||
39 | */ | ||
40 | virtual ~XmlReader(); | ||
41 | |||
42 | /** | ||
43 | * Build a document based on some kind of input. This is called | ||
44 | * automatically by the constructor. | ||
45 | */ | ||
46 | bool buildDoc(); | ||
47 | |||
48 | private: | ||
49 | /** | ||
50 | * This is called by the low level automoton in order to get the next | ||
51 | * character. This function should return a character at the current | ||
52 | * position plus nIndex, but does not increment the current character. | ||
53 | *@param nIndex The index of the character from the current stream position. | ||
54 | *@returns A single character at the requested position, or 0 for end of | ||
55 | * stream. | ||
56 | */ | ||
57 | virtual char getChar( int nIndex = 0 ); | ||
58 | |||
59 | /** | ||
60 | * Called to increment the current stream position by a single character. | ||
61 | */ | ||
62 | virtual void usedChar( int nAmnt = 1 ); | ||
63 | |||
64 | /** | ||
65 | * Automoton function: is whitespace. | ||
66 | *@param chr A character | ||
67 | *@returns True if chr is whitespace, false otherwise. | ||
68 | */ | ||
69 | bool isws( char chr ); | ||
70 | |||
71 | /** | ||
72 | * Automoton function: ws. Skips sections of whitespace. | ||
73 | *@returns True if everything was ok, False for end of stream. | ||
74 | */ | ||
75 | bool ws(); | ||
76 | |||
77 | /** | ||
78 | * Automoton function: node. Processes an XmlNode | ||
79 | *@returns True if everything was ok, False for end of stream. | ||
80 | */ | ||
81 | bool node(); | ||
82 | |||
83 | /** | ||
84 | * Automoton function: startNode. Processes the begining of a node. | ||
85 | *@returns True if everything was ok, False for end of stream. | ||
86 | */ | ||
87 | bool startNode(); | ||
88 | |||
89 | /** | ||
90 | * Automoton function: name. Processes the name of a node. | ||
91 | *@returns True if everything was ok, False for end of stream. | ||
92 | */ | ||
93 | bool name(); | ||
94 | |||
95 | /** | ||
96 | * Automoton function: textDecl. Processes the xml text decleration, if | ||
97 | * there is one. | ||
98 | */ | ||
99 | void textDecl(); | ||
100 | |||
101 | /** | ||
102 | * Automoton function: entity. Processes an entity from the header. | ||
103 | */ | ||
104 | void entity(); | ||
105 | |||
106 | /** | ||
107 | * Adds an entity to the list, if it doesn't already exist. | ||
108 | *@param name The name of the entity | ||
109 | *@param value The value of the entity | ||
110 | */ | ||
111 | void addEntity( const Bu::FString &name, const Bu::FString &value ); | ||
112 | |||
113 | Bu::FString getEscape(); | ||
114 | |||
115 | /** | ||
116 | * Automoton function: paramlist. Processes a list of node params. | ||
117 | *@returns True if everything was ok, False for end of stream. | ||
118 | */ | ||
119 | bool paramlist(); | ||
120 | |||
121 | /** | ||
122 | * Automoton function: param. Processes a single parameter. | ||
123 | *@returns True if everything was ok, False for end of stream. | ||
124 | */ | ||
125 | bool param(); | ||
126 | |||
127 | /** | ||
128 | * Automoton function: content. Processes node content. | ||
129 | *@returns True if everything was ok, False for end of stream. | ||
130 | */ | ||
131 | bool content(); | ||
132 | |||
133 | Bu::FString sContent; /**< buffer for the current node's content. */ | ||
134 | Bu::FString sParamName; /**< buffer for the current param's name. */ | ||
135 | Bu::FString sParamValue; /**< buffer for the current param's value. */ | ||
136 | Bu::Stream &sIn; | ||
137 | bool bStrip; /**< Are we stripping whitespace? */ | ||
138 | |||
139 | Bu::Hash<Bu::FString,Bu::FString> htEntity; /**< Entity type definitions. */ | ||
140 | |||
141 | Bu::FString sBuf; | ||
142 | }; | ||
143 | |||
144 | #endif | ||
diff --git a/src/old/xmlwriter.cpp b/src/old/xmlwriter.cpp new file mode 100644 index 0000000..7dc6ca9 --- /dev/null +++ b/src/old/xmlwriter.cpp | |||
@@ -0,0 +1,167 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include "xmlwriter.h" | ||
4 | |||
5 | XmlWriter::XmlWriter( const Bu::FString &sIndent, XmlNode *pRoot ) : | ||
6 | XmlDocument( pRoot ), | ||
7 | sIndent( sIndent ) | ||
8 | { | ||
9 | } | ||
10 | |||
11 | XmlWriter::~XmlWriter() | ||
12 | { | ||
13 | } | ||
14 | |||
15 | void XmlWriter::write() | ||
16 | { | ||
17 | write( getRoot(), sIndent.c_str() ); | ||
18 | } | ||
19 | |||
20 | void XmlWriter::write( XmlNode *pRoot, const Bu::FString &sIndent ) | ||
21 | { | ||
22 | writeNode( pRoot, 0, sIndent ); | ||
23 | } | ||
24 | |||
25 | void XmlWriter::closeNode() | ||
26 | { | ||
27 | XmlDocument::closeNode(); | ||
28 | |||
29 | if( isCompleted() ) | ||
30 | { | ||
31 | write( getRoot(), sIndent.c_str() ); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | void XmlWriter::writeIndent( int nIndent, const Bu::FString &sIndent ) | ||
36 | { | ||
37 | if( sIndent == NULL ) return; | ||
38 | for( int j = 0; j < nIndent; j++ ) | ||
39 | { | ||
40 | writeString( sIndent ); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | Bu::FString XmlWriter::escape( const Bu::FString &sIn ) | ||
45 | { | ||
46 | Bu::FString sOut; | ||
47 | |||
48 | int nMax = sIn.getSize(); | ||
49 | for( int j = 0; j < nMax; j++ ) | ||
50 | { | ||
51 | char c = sIn[j]; | ||
52 | if( ((c >= ' ' && c <= '9') || | ||
53 | (c >= 'a' && c <= 'z') || | ||
54 | (c >= 'A' && c <= 'Z') ) && | ||
55 | (c != '\"' && c != '\'' && c != '&') | ||
56 | ) | ||
57 | { | ||
58 | sOut += c; | ||
59 | } | ||
60 | else | ||
61 | { | ||
62 | sOut += "&#"; | ||
63 | char buf[4]; | ||
64 | sprintf( buf, "%u", (unsigned char)c ); | ||
65 | sOut += buf; | ||
66 | sOut += ';'; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | return sOut; | ||
71 | } | ||
72 | |||
73 | void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ) | ||
74 | { | ||
75 | for( int j = 0; j < pNode->getNumProperties(); j++ ) | ||
76 | { | ||
77 | writeString(" "); | ||
78 | //writeString( pNode->getPropertyName( j ) ); | ||
79 | writeString("=\""); | ||
80 | //writeString( escape( pNode->getProperty( j ) ).c_str() ); | ||
81 | writeString("\""); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ) | ||
86 | { | ||
87 | if( pNode->hasChildren() ) | ||
88 | { | ||
89 | writeIndent( nIndent, sIndent ); | ||
90 | writeString("<"); | ||
91 | writeString( pNode->getName() ); | ||
92 | writeNodeProps( pNode, nIndent, sIndent ); | ||
93 | if( sIndent != "" ) | ||
94 | writeString(">\n"); | ||
95 | else | ||
96 | writeString(">"); | ||
97 | /* | ||
98 | if( pNode->getContent( 0 ) ) | ||
99 | { | ||
100 | writeIndent( nIndent+1, sIndent ); | ||
101 | if( sIndent != "" ) | ||
102 | { | ||
103 | writeString( pNode->getContent( 0 ) ); | ||
104 | writeString("\n"); | ||
105 | } | ||
106 | else | ||
107 | writeString( pNode->getContent( 0 ) ); | ||
108 | } | ||
109 | |||
110 | int nNumChildren = pNode->getNumChildren(); | ||
111 | for( int j = 0; j < nNumChildren; j++ ) | ||
112 | { | ||
113 | writeNode( pNode->getChild( j ), nIndent+1, sIndent ); | ||
114 | if( pNode->getContent( j+1 ) ) | ||
115 | { | ||
116 | writeIndent( nIndent+1, sIndent ); | ||
117 | if( sIndent ) | ||
118 | { | ||
119 | writeString( pNode->getContent( j+1 ) ); | ||
120 | writeString("\n"); | ||
121 | } | ||
122 | else | ||
123 | writeString( pNode->getContent( j+1 ) ); | ||
124 | } | ||
125 | } | ||
126 | */ | ||
127 | writeIndent( nIndent, sIndent ); | ||
128 | if( sIndent != "" ) | ||
129 | { | ||
130 | writeString("</"); | ||
131 | writeString( pNode->getName() ); | ||
132 | writeString(">\n"); | ||
133 | } | ||
134 | else | ||
135 | { | ||
136 | writeString("</"); | ||
137 | writeString( pNode->getName() ); | ||
138 | writeString(">"); | ||
139 | } | ||
140 | }/* | ||
141 | else if( pNode->getContent() ) | ||
142 | { | ||
143 | writeIndent( nIndent, sIndent ); | ||
144 | writeString("<"); | ||
145 | writeString( pNode->getName() ); | ||
146 | writeNodeProps( pNode, nIndent, sIndent ); | ||
147 | writeString(">"); | ||
148 | writeString( pNode->getContent() ); | ||
149 | writeString("</"); | ||
150 | writeString( pNode->getName() ); | ||
151 | writeString(">"); | ||
152 | if( sIndent ) | ||
153 | writeString("\n"); | ||
154 | }*/ | ||
155 | else | ||
156 | { | ||
157 | writeIndent( nIndent, sIndent ); | ||
158 | writeString("<"); | ||
159 | writeString( pNode->getName() ); | ||
160 | writeNodeProps( pNode, nIndent, sIndent ); | ||
161 | if( sIndent != "" ) | ||
162 | writeString("/>\n"); | ||
163 | else | ||
164 | writeString("/>"); | ||
165 | } | ||
166 | } | ||
167 | |||
diff --git a/src/old/xmlwriter.h b/src/old/xmlwriter.h new file mode 100644 index 0000000..7e3c876 --- /dev/null +++ b/src/old/xmlwriter.h | |||
@@ -0,0 +1,96 @@ | |||
1 | #ifndef XMLWRITER | ||
2 | #define XMLWRITER | ||
3 | |||
4 | #include "xmlnode.h" | ||
5 | #include "xmldocument.h" | ||
6 | |||
7 | /** | ||
8 | * Implements xml writing in the XML standard format. Also allows you to | ||
9 | * break that format and auto-indent your exported xml data for ease of | ||
10 | * reading. The auto-indenting will only be applied to sections that | ||
11 | * have no content of their own already. This means that except for | ||
12 | * whitespace all of your data will be preserved perfectly. | ||
13 | * You can create an XmlWriter object around a file, or access the static | ||
14 | * write function directly and just hand it a filename and a root XmlNode. | ||
15 | * When using an XmlWriter object the interface is identicle to that of | ||
16 | * the XmlDocument class, so reference that class for API info. However | ||
17 | * when the initial (or root) node is closed, and the document is finished | ||
18 | * the file will be created and written to automatically. The user can | ||
19 | * check to see if this is actually true by calling the isFinished | ||
20 | * function in the XmlDocument class. | ||
21 | *@author Mike Buland | ||
22 | */ | ||
23 | class XmlWriter : public XmlDocument | ||
24 | { | ||
25 | public: | ||
26 | /** | ||
27 | * Construct a standard XmlWriter. | ||
28 | *@param sIndent Set this to something other than NULL to include it as an | ||
29 | * indent before each node in the output that doesn't already have content. | ||
30 | * If you are using the whitespace stripping option in the XmlReader and set | ||
31 | * this to a tab or some spaces it will never effect the content of your | ||
32 | * file. | ||
33 | */ | ||
34 | XmlWriter( const Bu::FString &sIndent="", XmlNode *pRoot=NULL ); | ||
35 | |||
36 | /** | ||
37 | * Destroy the writer. | ||
38 | */ | ||
39 | virtual ~XmlWriter(); | ||
40 | |||
41 | /** | ||
42 | * This override of the parent class closeNode function calls the parent | ||
43 | * class, but also triggers a write operation when the final node is closed. | ||
44 | * This means that by checking the isCompleted() function the user may also | ||
45 | * check to see if their file has been written or not. | ||
46 | */ | ||
47 | void closeNode(); | ||
48 | |||
49 | void write(); | ||
50 | |||
51 | private: | ||
52 | Bu::FString sIndent; /**< The indent string */ | ||
53 | |||
54 | Bu::FString escape( const Bu::FString &sIn ); | ||
55 | |||
56 | /** | ||
57 | * Write the file. | ||
58 | *@param pNode The root node | ||
59 | *@param sIndent The indent text. | ||
60 | */ | ||
61 | void write( XmlNode *pNode, const Bu::FString &sIndent ); | ||
62 | |||
63 | /** | ||
64 | * Write a node in the file, including children. | ||
65 | *@param pNode The node to write. | ||
66 | *@param nIndent The indent level (the number of times to include sIndent) | ||
67 | *@param sIndent The indent text. | ||
68 | */ | ||
69 | void writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ); | ||
70 | |||
71 | /** | ||
72 | * Write the properties of a node. | ||
73 | *@param pNode The node who's properties to write. | ||
74 | *@param nIndent The indent level of the containing node | ||
75 | *@param sIndent The indent text. | ||
76 | */ | ||
77 | void writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent ); | ||
78 | |||
79 | /** | ||
80 | * Called to write the actual indent. | ||
81 | *@param nIndent The indent level. | ||
82 | *@param sIndent The indent text. | ||
83 | */ | ||
84 | void writeIndent( int nIndent, const Bu::FString &sIndent ); | ||
85 | |||
86 | /** | ||
87 | * This is the function that must be overridden in order to use this class. | ||
88 | * It must write the null-terminated string sString, minus the mull, | ||
89 | * verbatum to it's output device. Adding extra characters for any reason | ||
90 | * will break the XML formatting. | ||
91 | *@param sString The string data to write to the output. | ||
92 | */ | ||
93 | virtual void writeString( const Bu::FString &sString ) = 0; | ||
94 | }; | ||
95 | |||
96 | #endif | ||