vfs: check userland buffers before reading them.
[haiku.git] / src / apps / cortex / Persistence / Importer.cpp
blob0b35420c2d23d3543735377237d6d3ca79e19551
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 // Importer.cpp
33 // e.moon 28jun99
35 #include "Importer.h"
36 #include <stdexcept>
38 #include <Autolock.h>
39 #include <Debug.h>
41 using namespace std;
43 __USE_CORTEX_NAMESPACE
45 // -------------------------------------------------------- //
46 // expat hooks
47 // -------------------------------------------------------- //
49 void _oc_handle_start(
50 void* pUser,
51 const XML_Char* pName,
52 const XML_Char** ppAtts) {
53 ((Importer*)pUser)->xmlElementStart(pName, ppAtts);
56 void _oc_handle_end(
57 void* pUser,
58 const XML_Char* pName) {
59 ((Importer*)pUser)->xmlElementEnd(pName);
62 void _oc_handle_pi(
63 void* pUser,
64 const XML_Char* pTarget,
65 const XML_Char* pData) {
66 ((Importer*)pUser)->xmlProcessingInstruction(pTarget, pData);
69 void _oc_handle_char(
70 void* pUser,
71 const XML_Char* pData,
72 int length) {
73 ((Importer*)pUser)->xmlCharacterData(pData, length);
76 void _oc_handle_default(
77 void* pUser,
78 const XML_Char* pData,
79 int length) {
80 ((Importer*)pUser)->xmlDefaultData(pData, length);
83 // -------------------------------------------------------- //
84 // ctor/dtor
85 // -------------------------------------------------------- //
87 Importer::~Importer() {
88 // clean up
89 freeParser();
91 delete m_context;
95 Importer::Importer(
96 list<BString>& errors) :
98 m_parser(0),
99 m_docType(0),
100 m_identify(false),
101 m_context(new ImportContext(errors)),
102 m_rootObject(0) {
104 initParser();
107 Importer::Importer(
108 ImportContext* context) :
110 m_parser(0),
111 m_docType(0),
112 m_identify(false),
113 m_context(context),
114 m_rootObject(0) {
116 ASSERT(m_context);
118 initParser();
121 Importer::Importer(
122 list<BString>& errors,
123 IPersistent* rootObject,
124 XML::DocumentType* docType) :
126 m_parser(0),
127 m_docType(docType),
128 m_identify(false),
129 m_context(new ImportContext(errors)),
130 m_rootObject(rootObject) {
132 ASSERT(rootObject);
133 ASSERT(docType);
135 initParser();
138 Importer::Importer(
139 ImportContext* context,
140 IPersistent* rootObject,
141 XML::DocumentType* docType) :
143 m_parser(0),
144 m_docType(docType),
145 m_identify(false),
146 m_context(context),
147 m_rootObject(rootObject) {
149 ASSERT(m_context);
150 ASSERT(rootObject);
151 ASSERT(docType);
153 initParser();
156 // -------------------------------------------------------- //
157 // accessors
158 // -------------------------------------------------------- //
160 // the import context
161 const ImportContext& Importer::context() const {
162 return *m_context;
165 // matched (or provided) document type
166 XML::DocumentType* Importer::docType() const {
167 return m_docType;
170 // completed object (available if
171 // context().state() == ImportContext::COMPLETE, or
172 // if a root object was provided to the ctor)
173 IPersistent* Importer::target() const {
174 return m_rootObject;
177 // -------------------------------------------------------- //
178 // operations
179 // -------------------------------------------------------- //
181 // put the importer into 'identify mode'
182 // (disengaged once the first element is encountered)
183 void Importer::setIdentifyMode() {
184 reset();
185 m_docType = 0;
186 m_identify = true;
189 void Importer::reset() {
190 // doesn't forget document type from identify cycle!
192 m_identify = false;
193 m_context->reset();
194 m_rootObject = 0;
197 // handle a buffer; return false if an error occurs
198 bool Importer::parseBuffer(
199 const char* pBuffer,
200 uint32 length,
201 bool last) {
203 ASSERT(m_parser);
205 int err = XML_Parse(m_parser, pBuffer, length, last);
207 if(!err) {
208 BString str = "Parse Error: ";
209 str << XML_ErrorString(XML_GetErrorCode(m_parser));
210 m_context->reportError(str.String());
211 return false;
213 } else
214 return true;
217 // -------------------------------------------------------- //
218 // internal operations
219 // -------------------------------------------------------- //
221 // create & initialize parser
222 void Importer::initParser() {
223 ASSERT(!m_parser);
224 m_parser = XML_ParserCreate(0);
225 m_context->m_pParser = m_parser;
227 XML_SetElementHandler(
228 m_parser,
229 &_oc_handle_start,
230 &_oc_handle_end);
232 XML_SetProcessingInstructionHandler(
233 m_parser,
234 &_oc_handle_pi);
236 XML_SetCharacterDataHandler(
237 m_parser,
238 &_oc_handle_char);
240 XML_SetDefaultHandlerExpand(
241 m_parser,
242 &_oc_handle_default);
244 XML_SetUserData(
245 m_parser,
246 (void*)this);
249 // clean up the parser
250 void Importer::freeParser() {
251 ASSERT(m_parser);
252 XML_ParserFree(m_parser);
253 m_parser = 0;
256 // -------------------------------------------------------- //
257 // XML parser event hooks
258 // -------------------------------------------------------- //
260 void Importer::xmlElementStart(
261 const char* pName,
262 const char** ppAttributes) {
264 if(m_context->m_state != ImportContext::PARSING)
265 return;
267 IPersistent* target = 0;
269 if(!m_context->m_elementStack.size()) {
270 // this is the first element; identify or verify document type
272 if(m_rootObject) {
273 // test against expected document type
274 ASSERT(m_docType);
275 if(m_docType->rootElement != pName) {
276 BString err("Unexpected document element (should be <");
277 err << m_docType->rootElement << "/>";
278 m_context->reportError(err.String());
279 return;
282 // target the provided root object
283 target = m_rootObject;
285 else {
286 // look up doc type
287 BAutolock _l(XML::s_docTypeLock);
288 XML::doc_type_map::iterator it = XML::s_docTypeMap.find(
289 BString(pName));
291 if(it != XML::s_docTypeMap.end())
292 m_docType = (*it).second;
293 else {
294 // whoops, don't know how to handle this element:
295 BString err("No document type registered for element '");
296 err << pName << "'.";
297 m_context->reportError(err.String());
298 return;
301 if(m_identify) {
302 // end of identify cycle
303 m_context->m_state = ImportContext::COMPLETE;
304 return;
308 // at this point, there'd better be a valid document type
309 ASSERT(m_docType);
311 // push element name onto the stack
312 m_context->m_elementStack.push_back(pName);
314 // try to create an object for this element if necessary
315 if(!target)
316 target = m_docType->objectFor(pName);
318 if(target) {
319 // call 'begin import' hook
320 m_context->m_objectStack.push_back(
321 make_pair(m_context->element(), target));
322 target->xmlImportBegin(*m_context);
324 // error? bail
325 if(m_context->state() != ImportContext::PARSING)
326 return;
328 // walk attributes
329 while(*ppAttributes) {
330 target->xmlImportAttribute(
331 ppAttributes[0],
332 ppAttributes[1],
333 *m_context);
335 // error? bail
336 if(m_context->state() != ImportContext::PARSING)
337 return;
339 ppAttributes += 2;
341 } else {
342 // no object directly maps to this element; hand to
343 // the current focus object
345 ASSERT(m_context->m_objectStack.size());
346 IPersistent* curObject = m_context->m_objectStack.back().second;
347 ASSERT(curObject);
349 curObject->xmlImportChildBegin(
350 pName,
351 *m_context);
353 // error? bail
354 if(m_context->state() != ImportContext::PARSING)
355 return;
357 // walk attributes
358 while(*ppAttributes) {
359 curObject->xmlImportChildAttribute(
360 ppAttributes[0],
361 ppAttributes[1],
362 *m_context);
364 // error? bail
365 if(m_context->state() != ImportContext::PARSING)
366 return;
368 ppAttributes += 2;
373 void Importer::xmlElementEnd(
374 const char* pName) {
376 if(m_context->m_state != ImportContext::PARSING)
377 return;
378 ASSERT(m_docType);
380 // PRINT(("Importer::xmlElementEnd(): %s\n", pName));
382 // compare name to element on top of stack
383 if(!m_context->m_elementStack.size() ||
384 m_context->m_elementStack.back() != pName) {
385 m_context->reportError("Mismatched end tag.");
386 return;
389 // see if it matches the topmost object
390 IPersistent* pObject = 0;
391 if(!m_context->m_objectStack.size()) {
392 m_context->reportError("No object being constructed.");
393 return;
395 if(m_context->m_objectStack.back().first == m_context->element()) {
396 // matched; pop it
397 pObject = m_context->m_objectStack.back().second;
398 m_context->m_objectStack.pop_back();
401 if(pObject) {
402 // notify object that import is complete
403 pObject->xmlImportComplete(
404 *m_context);
406 // error? bail
407 if(m_context->state() != ImportContext::PARSING)
408 return;
410 if(m_context->m_objectStack.size()) {
411 // hand the newly-constructed child to its parent
412 m_context->m_objectStack.back().second->xmlImportChild(
413 pObject,
414 *m_context);
415 } else {
416 // done
417 ASSERT(m_context->m_elementStack.size() == 1);
418 m_context->m_state = ImportContext::COMPLETE;
419 if(m_rootObject) {
420 ASSERT(m_rootObject == pObject);
421 } else
422 m_rootObject = pObject;
425 else {
426 // notify current topmost object
427 ASSERT(m_context->m_objectStack.size());
428 IPersistent* curObject = m_context->m_objectStack.back().second;
429 ASSERT(curObject);
431 curObject->xmlImportChildComplete(
432 pName,
433 *m_context);
436 // remove entry from element stack
437 m_context->m_elementStack.pop_back();
438 ASSERT(m_context->m_objectStack.size() <= m_context->m_elementStack.size());
441 void Importer::xmlProcessingInstruction(
442 const char* pTarget,
443 const char* pData) {
445 if(m_context->m_state != ImportContext::PARSING)
446 return;
447 // PRINT(("Importer::xmlProcessingInstruction(): %s, %s\n",
448 // pTarget, pData));
452 // not 0-terminated
453 void Importer::xmlCharacterData(
454 const char* pData,
455 int32 length) {
457 if(m_context->m_state != ImportContext::PARSING)
458 return;
460 // see if the current element matches the topmost object
461 IPersistent* pObject = 0;
462 if(!m_context->m_objectStack.size()) {
463 m_context->reportError("No object being constructed.");
464 return;
467 pObject = m_context->m_objectStack.back().second;
468 if(m_context->m_objectStack.back().first == m_context->element()) {
470 pObject->xmlImportContent(
471 pData,
472 length,
473 *m_context);
475 else {
476 pObject->xmlImportChildContent(
477 pData,
478 length,
479 *m_context);
483 // not 0-terminated
484 void Importer::xmlDefaultData(
485 const char* pData,
486 int32 length) {
488 if(m_context->m_state != ImportContext::PARSING)
489 return;
490 // PRINT(("Importer::xmlDefaultData()\n"));
493 // END -- Importer.cpp --