xref: /haiku/src/apps/cortex/Persistence/XML.cpp (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
1 // XML.cpp
2 // e.moon 1jul99
3 
4 #include "XML.h"
5 #include "Importer.h"
6 
7 #include <Autolock.h>
8 #include <Debug.h>
9 
10 #include "array_delete.h"
11 #include "set_tools.h"
12 
13 using namespace std;
14 
15 __USE_CORTEX_NAMESPACE
16 
17 // -------------------------------------------------------- //
18 // static members
19 // -------------------------------------------------------- //
20 
21 XML::doc_type_map XML::s_docTypeMap;
22 BLocker XML::s_docTypeLock("XML::s_docTypeLock");
23 
24 const BMimeType XML::DocumentType::s_defaultMimeType("text/xml");
25 
26 // -------------------------------------------------------- //
27 // document type operations
28 // -------------------------------------------------------- //
29 
30 // takes responsibility for the given type object
31 
32 /*static*/
33 void XML::AddDocumentType(
34 	XML::DocumentType*					type) {
35 
36 	ASSERT(type);
37 	BAutolock _l(s_docTypeLock);
38 
39 //	s_docTypeMap.insert(
40 //		make_pair(type->rootElement, type));
41 	s_docTypeMap.insert(
42 		pair<const BString, XML::DocumentType*>(type->rootElement, type));
43 }
44 
45 // -------------------------------------------------------- //
46 // import/export operations
47 // -------------------------------------------------------- //
48 
49 // identify object in stream
50 // returns:
51 // - B_OK on success, or
52 // - B_BAD_TYPE if no document type matches the root
53 //   element of the stream, or
54 // - B_IO_ERROR if the document is malformed, or if a
55 //   read error occurs.
56 
57 /*static*/
58 status_t XML::Identify(
59 	BDataIO*										stream,
60 	DocumentType**							outType,
61 	list<BString>*							outErrors) {
62 
63 	ASSERT(stream);
64 
65 	// prepare the input buffer
66 	const uint32 bufferSize = 4096;
67 	char* buffer = new char[bufferSize];
68 	array_delete<char> _d(buffer);
69 
70 	// prepare an Importer to figure document type (from first element)
71 	Importer i(*outErrors);
72 	i.setIdentifyMode();
73 
74 	while(
75 		i.context().state() == ImportContext::PARSING) {
76 
77 		// read chunk (no 0 terminator)
78 		ssize_t readCount = stream->Read(buffer, bufferSize);
79 		if(readCount == 0)
80 			 // done
81 			break;
82 		else if(readCount < 0) {
83 			// error
84 			BString err = "Read error: '";
85 			err << strerror(readCount) << "'; ABORTING.";
86 			outErrors->push_back(err);
87 
88 			return B_IO_ERROR;
89 		}
90 
91 		// feed to parser
92 		if(!i.parseBuffer(
93 			buffer, readCount, !stream)) {
94 			break;
95 		}
96 	}
97 
98 	// return found type
99 	if(i.docType()) {
100 		*outType = i.docType();
101 		return B_OK;
102 	}
103 	else return B_BAD_TYPE;
104 }
105 
106 // read the root object from the given stream
107 
108 /*static*/
109 status_t XML::Read(
110 	BDataIO*										stream,
111 	IPersistent**								outObject,
112 	list<BString>*							outErrors) {
113 
114 	Importer i(*outErrors);
115 	status_t err = _DoRead(stream, i, outErrors);
116 	if(err == B_OK) {
117 		// return completed object
118 		ASSERT(i.target());
119 		*outObject = i.target();
120 	}
121 	return err;
122 }
123 
124 /*static*/
125 status_t XML::Read(
126 	BDataIO*										stream,
127 	IPersistent**								outObject,
128 	ImportContext*							context) {
129 
130 	Importer i(context);
131 	status_t err = _DoRead(stream, i, &context->errors());
132 	if(err == B_OK) {
133 		// return completed object
134 		ASSERT(i.target());
135 		*outObject = i.target();
136 	}
137 	return err;
138 }
139 
140 // [e.moon 26nov99]
141 // populate the provided root object from the given
142 // XML stream.  you need to give the expected root
143 // (document) element name corresponding to the
144 // item you provide.
145 // returns:
146 // - B_OK on success, or
147 // - B_IO_ERROR if the document is malformed, or if a
148 //   read error occurs, or
149 // - B_ERROR
150 
151 /*static*/
152 status_t XML::Read(
153 	BDataIO*										stream,
154 	IPersistent*								rootObject,
155 	XML::DocumentType*					documentType,
156 	list<BString>*							outErrors) {
157 
158 	Importer i(*outErrors, rootObject, documentType);
159 	return _DoRead(stream, i, outErrors);
160 }
161 
162 /*static*/
163 status_t XML::Read(
164 	BDataIO*										stream,
165 	IPersistent*								rootObject,
166 	XML::DocumentType*					documentType,
167 	ImportContext*							context) {
168 
169 	Importer i(context, rootObject, documentType);
170 	return _DoRead(stream, i, &context->errors());
171 }
172 
173 /*static*/
174 status_t XML::_DoRead(
175 	BDataIO*										stream,
176 	Importer&										i,
177 	list<BString>*							outErrors) {
178 
179 	// prepare the input buffer
180 	const uint32 bufferSize = 4096;
181 	char* buffer = new char[bufferSize];
182 	array_delete<char> _d(buffer);
183 
184 	while(
185 		i.context().state() == ImportContext::PARSING) {
186 
187 		// read chunk (no 0 terminator)
188 		ssize_t readCount = stream->Read(buffer, bufferSize);
189 		if(readCount == 0)
190 			 // done
191 			break;
192 		else if(readCount < 0) {
193 			// error
194 			BString err = "Read error: '";
195 			err << strerror(readCount) << "'; ABORTING.";
196 			outErrors->push_back(err);
197 			return B_IO_ERROR;
198 		}
199 
200 		// feed to parser
201 		if(!i.parseBuffer(
202 			buffer, readCount, !stream)) {
203 			break;
204 		}
205 	}
206 
207 	status_t err = B_ERROR;
208 	if(i.context().state() == ImportContext::COMPLETE)
209 		err = B_OK;
210 
211 	// clean up
212 	return err;
213 }
214 
215 // write the given object to the given stream
216 
217 /*static*/
218 status_t XML::Write(
219 	BDataIO*										stream,
220 	IPersistent*								object,
221 	BString*										outError) {
222 
223 	ASSERT(object);
224 
225 	ExportContext context(stream);
226 	status_t err = context.writeObject(object);
227 	if(err < B_OK)
228 		*outError = context.errorText();
229 	return err;
230 }
231 
232 // -------------------------------------------------------- //
233 // XML::DocumentType
234 // -------------------------------------------------------- //
235 
236 class _NullMapping : public XMLElementMapping {
237 public:
238 	_NullMapping(
239 		const char*									_element) :
240 		XMLElementMapping(_element) {}
241 
242 	IPersistent* create() const { return 0; }
243 };
244 
245 XML::DocumentType::~DocumentType() {
246 	// clean up
247 	ptr_set_delete(m_mappingSet.begin(), m_mappingSet.end());
248 }
249 
250 XML::DocumentType::DocumentType(
251 	const char*									_rootElement,
252 	const char*									_mimeType) :
253 	rootElement(_rootElement),
254 	mimeType(_mimeType ? _mimeType : s_defaultMimeType.Type()) {}
255 
256 // *** 'factory' interface
257 
258 // The DocumentType takes ownership of the given mapping
259 // object.  If a mapping for the element already exists,
260 // the provided object is deleted and the method returns
261 // B_NAME_IN_USE.
262 status_t XML::DocumentType::addMapping(
263 	XMLElementMapping*					mapping) {
264 
265 	pair<mapping_set::iterator, bool> ret =	m_mappingSet.insert(mapping);
266 	if(!ret.second) {
267 		delete mapping;
268 		return B_NAME_IN_USE;
269 	} else
270 		return B_OK;
271 }
272 
273 IPersistent* XML::DocumentType::objectFor(
274 	const char*									element) {
275 
276 	_NullMapping m(element);
277 	mapping_set::iterator it = m_mappingSet.find(&m);
278 
279 	return (it != m_mappingSet.end()) ?
280 		(*it)->create() : 0;
281 }
282 
283 // END -- XML.cpp --
284