2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
43 __USE_CORTEX_NAMESPACE
45 // -------------------------------------------------------- //
47 // -------------------------------------------------------- //
49 void _oc_handle_start(
51 const XML_Char
* pName
,
52 const XML_Char
** ppAtts
) {
53 ((Importer
*)pUser
)->xmlElementStart(pName
, ppAtts
);
58 const XML_Char
* pName
) {
59 ((Importer
*)pUser
)->xmlElementEnd(pName
);
64 const XML_Char
* pTarget
,
65 const XML_Char
* pData
) {
66 ((Importer
*)pUser
)->xmlProcessingInstruction(pTarget
, pData
);
71 const XML_Char
* pData
,
73 ((Importer
*)pUser
)->xmlCharacterData(pData
, length
);
76 void _oc_handle_default(
78 const XML_Char
* pData
,
80 ((Importer
*)pUser
)->xmlDefaultData(pData
, length
);
83 // -------------------------------------------------------- //
85 // -------------------------------------------------------- //
87 Importer::~Importer() {
96 list
<BString
>& errors
) :
101 m_context(new ImportContext(errors
)),
108 ImportContext
* context
) :
122 list
<BString
>& errors
,
123 IPersistent
* rootObject
,
124 XML::DocumentType
* docType
) :
129 m_context(new ImportContext(errors
)),
130 m_rootObject(rootObject
) {
139 ImportContext
* context
,
140 IPersistent
* rootObject
,
141 XML::DocumentType
* docType
) :
147 m_rootObject(rootObject
) {
156 // -------------------------------------------------------- //
158 // -------------------------------------------------------- //
160 // the import context
161 const ImportContext
& Importer::context() const {
165 // matched (or provided) document type
166 XML::DocumentType
* Importer::docType() const {
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 {
177 // -------------------------------------------------------- //
179 // -------------------------------------------------------- //
181 // put the importer into 'identify mode'
182 // (disengaged once the first element is encountered)
183 void Importer::setIdentifyMode() {
189 void Importer::reset() {
190 // doesn't forget document type from identify cycle!
197 // handle a buffer; return false if an error occurs
198 bool Importer::parseBuffer(
205 int err
= XML_Parse(m_parser
, pBuffer
, length
, last
);
208 BString str
= "Parse Error: ";
209 str
<< XML_ErrorString(XML_GetErrorCode(m_parser
));
210 m_context
->reportError(str
.String());
217 // -------------------------------------------------------- //
218 // internal operations
219 // -------------------------------------------------------- //
221 // create & initialize parser
222 void Importer::initParser() {
224 m_parser
= XML_ParserCreate(0);
225 m_context
->m_pParser
= m_parser
;
227 XML_SetElementHandler(
232 XML_SetProcessingInstructionHandler(
236 XML_SetCharacterDataHandler(
240 XML_SetDefaultHandlerExpand(
242 &_oc_handle_default
);
249 // clean up the parser
250 void Importer::freeParser() {
252 XML_ParserFree(m_parser
);
256 // -------------------------------------------------------- //
257 // XML parser event hooks
258 // -------------------------------------------------------- //
260 void Importer::xmlElementStart(
262 const char** ppAttributes
) {
264 if(m_context
->m_state
!= ImportContext::PARSING
)
267 IPersistent
* target
= 0;
269 if(!m_context
->m_elementStack
.size()) {
270 // this is the first element; identify or verify document type
273 // test against expected document type
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());
282 // target the provided root object
283 target
= m_rootObject
;
287 BAutolock
_l(XML::s_docTypeLock
);
288 XML::doc_type_map::iterator it
= XML::s_docTypeMap
.find(
291 if(it
!= XML::s_docTypeMap
.end())
292 m_docType
= (*it
).second
;
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());
302 // end of identify cycle
303 m_context
->m_state
= ImportContext::COMPLETE
;
308 // at this point, there'd better be a valid document type
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
316 target
= m_docType
->objectFor(pName
);
319 // call 'begin import' hook
320 m_context
->m_objectStack
.push_back(
321 make_pair(m_context
->element(), target
));
322 target
->xmlImportBegin(*m_context
);
325 if(m_context
->state() != ImportContext::PARSING
)
329 while(*ppAttributes
) {
330 target
->xmlImportAttribute(
336 if(m_context
->state() != ImportContext::PARSING
)
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
;
349 curObject
->xmlImportChildBegin(
354 if(m_context
->state() != ImportContext::PARSING
)
358 while(*ppAttributes
) {
359 curObject
->xmlImportChildAttribute(
365 if(m_context
->state() != ImportContext::PARSING
)
373 void Importer::xmlElementEnd(
376 if(m_context
->m_state
!= ImportContext::PARSING
)
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.");
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.");
395 if(m_context
->m_objectStack
.back().first
== m_context
->element()) {
397 pObject
= m_context
->m_objectStack
.back().second
;
398 m_context
->m_objectStack
.pop_back();
402 // notify object that import is complete
403 pObject
->xmlImportComplete(
407 if(m_context
->state() != ImportContext::PARSING
)
410 if(m_context
->m_objectStack
.size()) {
411 // hand the newly-constructed child to its parent
412 m_context
->m_objectStack
.back().second
->xmlImportChild(
417 ASSERT(m_context
->m_elementStack
.size() == 1);
418 m_context
->m_state
= ImportContext::COMPLETE
;
420 ASSERT(m_rootObject
== pObject
);
422 m_rootObject
= pObject
;
426 // notify current topmost object
427 ASSERT(m_context
->m_objectStack
.size());
428 IPersistent
* curObject
= m_context
->m_objectStack
.back().second
;
431 curObject
->xmlImportChildComplete(
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(
445 if(m_context
->m_state
!= ImportContext::PARSING
)
447 // PRINT(("Importer::xmlProcessingInstruction(): %s, %s\n",
453 void Importer::xmlCharacterData(
457 if(m_context
->m_state
!= ImportContext::PARSING
)
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.");
467 pObject
= m_context
->m_objectStack
.back().second
;
468 if(m_context
->m_objectStack
.back().first
== m_context
->element()) {
470 pObject
->xmlImportContent(
476 pObject
->xmlImportChildContent(
484 void Importer::xmlDefaultData(
488 if(m_context
->m_state
!= ImportContext::PARSING
)
490 // PRINT(("Importer::xmlDefaultData()\n"));
493 // END -- Importer.cpp --