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