vfs: check userland buffers before reading them.
[haiku.git] / src / apps / cortex / Persistence / XML.cpp
blob07f6c9f5193ff964d9be750c8ff8bd9f4d513262
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // XML.cpp
33 // e.moon 1jul99
35 #include "XML.h"
36 #include "Importer.h"
38 #include <Autolock.h>
39 #include <Debug.h>
41 #include "array_delete.h"
42 #include "set_tools.h"
44 using namespace std;
46 __USE_CORTEX_NAMESPACE
48 // -------------------------------------------------------- //
49 // static members
50 // -------------------------------------------------------- //
52 XML::doc_type_map XML::s_docTypeMap;
53 BLocker XML::s_docTypeLock("XML::s_docTypeLock");
55 const BMimeType XML::DocumentType::s_defaultMimeType("text/xml");
57 // -------------------------------------------------------- //
58 // document type operations
59 // -------------------------------------------------------- //
61 // takes responsibility for the given type object
63 /*static*/
64 void XML::AddDocumentType(
65 XML::DocumentType* type) {
67 ASSERT(type);
68 BAutolock _l(s_docTypeLock);
70 // s_docTypeMap.insert(
71 // make_pair(type->rootElement, type));
72 s_docTypeMap.insert(
73 pair<const BString, XML::DocumentType*>(type->rootElement, type));
76 // -------------------------------------------------------- //
77 // import/export operations
78 // -------------------------------------------------------- //
80 // identify object in stream
81 // returns:
82 // - B_OK on success, or
83 // - B_BAD_TYPE if no document type matches the root
84 // element of the stream, or
85 // - B_IO_ERROR if the document is malformed, or if a
86 // read error occurs.
88 /*static*/
89 status_t XML::Identify(
90 BDataIO* stream,
91 DocumentType** outType,
92 list<BString>* outErrors) {
94 ASSERT(stream);
96 // prepare the input buffer
97 const uint32 bufferSize = 4096;
98 char* buffer = new char[bufferSize];
99 array_delete<char> _d(buffer);
101 // prepare an Importer to figure document type (from first element)
102 Importer i(*outErrors);
103 i.setIdentifyMode();
105 while(
106 i.context().state() == ImportContext::PARSING) {
108 // read chunk (no 0 terminator)
109 ssize_t readCount = stream->Read(buffer, bufferSize);
110 if(readCount == 0)
111 // done
112 break;
113 else if(readCount < 0) {
114 // error
115 BString err = "Read error: '";
116 err << strerror(readCount) << "'; ABORTING.";
117 outErrors->push_back(err);
119 return B_IO_ERROR;
122 // feed to parser
123 if(!i.parseBuffer(
124 buffer, readCount, !stream)) {
125 break;
129 // return found type
130 if(i.docType()) {
131 *outType = i.docType();
132 return B_OK;
134 else return B_BAD_TYPE;
137 // read the root object from the given stream
139 /*static*/
140 status_t XML::Read(
141 BDataIO* stream,
142 IPersistent** outObject,
143 list<BString>* outErrors) {
145 Importer i(*outErrors);
146 status_t err = _DoRead(stream, i, outErrors);
147 if(err == B_OK) {
148 // return completed object
149 ASSERT(i.target());
150 *outObject = i.target();
152 return err;
155 /*static*/
156 status_t XML::Read(
157 BDataIO* stream,
158 IPersistent** outObject,
159 ImportContext* context) {
161 Importer i(context);
162 status_t err = _DoRead(stream, i, &context->errors());
163 if(err == B_OK) {
164 // return completed object
165 ASSERT(i.target());
166 *outObject = i.target();
168 return err;
171 // [e.moon 26nov99]
172 // populate the provided root object from the given
173 // XML stream. you need to give the expected root
174 // (document) element name corresponding to the
175 // item you provide.
176 // returns:
177 // - B_OK on success, or
178 // - B_IO_ERROR if the document is malformed, or if a
179 // read error occurs, or
180 // - B_ERROR
182 /*static*/
183 status_t XML::Read(
184 BDataIO* stream,
185 IPersistent* rootObject,
186 XML::DocumentType* documentType,
187 list<BString>* outErrors) {
189 Importer i(*outErrors, rootObject, documentType);
190 return _DoRead(stream, i, outErrors);
193 /*static*/
194 status_t XML::Read(
195 BDataIO* stream,
196 IPersistent* rootObject,
197 XML::DocumentType* documentType,
198 ImportContext* context) {
200 Importer i(context, rootObject, documentType);
201 return _DoRead(stream, i, &context->errors());
204 /*static*/
205 status_t XML::_DoRead(
206 BDataIO* stream,
207 Importer& i,
208 list<BString>* outErrors) {
210 // prepare the input buffer
211 const uint32 bufferSize = 4096;
212 char* buffer = new char[bufferSize];
213 array_delete<char> _d(buffer);
215 while(
216 i.context().state() == ImportContext::PARSING) {
218 // read chunk (no 0 terminator)
219 ssize_t readCount = stream->Read(buffer, bufferSize);
220 if(readCount == 0)
221 // done
222 break;
223 else if(readCount < 0) {
224 // error
225 BString err = "Read error: '";
226 err << strerror(readCount) << "'; ABORTING.";
227 outErrors->push_back(err);
228 return B_IO_ERROR;
231 // feed to parser
232 if(!i.parseBuffer(
233 buffer, readCount, !stream)) {
234 break;
238 status_t err = B_ERROR;
239 if(i.context().state() == ImportContext::COMPLETE)
240 err = B_OK;
242 // clean up
243 return err;
246 // write the given object to the given stream
248 /*static*/
249 status_t XML::Write(
250 BDataIO* stream,
251 IPersistent* object,
252 BString* outError) {
254 ASSERT(object);
256 ExportContext context(stream);
257 status_t err = context.writeObject(object);
258 if(err < B_OK)
259 *outError = context.errorText();
260 return err;
263 // -------------------------------------------------------- //
264 // XML::DocumentType
265 // -------------------------------------------------------- //
267 class _NullMapping : public XMLElementMapping {
268 public:
269 _NullMapping(
270 const char* _element) :
271 XMLElementMapping(_element) {}
273 IPersistent* create() const { return 0; }
276 XML::DocumentType::~DocumentType() {
277 // clean up
278 ptr_set_delete(m_mappingSet.begin(), m_mappingSet.end());
281 XML::DocumentType::DocumentType(
282 const char* _rootElement,
283 const char* _mimeType) :
284 rootElement(_rootElement),
285 mimeType(_mimeType ? _mimeType : s_defaultMimeType.Type()) {}
287 // *** 'factory' interface
289 // The DocumentType takes ownership of the given mapping
290 // object. If a mapping for the element already exists,
291 // the provided object is deleted and the method returns
292 // B_NAME_IN_USE.
293 status_t XML::DocumentType::addMapping(
294 XMLElementMapping* mapping) {
296 pair<mapping_set::iterator, bool> ret = m_mappingSet.insert(mapping);
297 if(!ret.second) {
298 delete mapping;
299 return B_NAME_IN_USE;
300 } else
301 return B_OK;
304 IPersistent* XML::DocumentType::objectFor(
305 const char* element) {
307 _NullMapping m(element);
308 mapping_set::iterator it = m_mappingSet.find(&m);
310 return (it != m_mappingSet.end()) ?
311 (*it)->create() : 0;
314 // END -- XML.cpp --