1 /* 2 * Copyright (c) 1999-2000, Eric Moon. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer. 11 * 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. 15 * 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. 18 * 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. 29 */ 30 31 32 // Importer.cpp 33 // e.moon 28jun99 34 35 #include "Importer.h" 36 #include <stdexcept> 37 38 #include <Autolock.h> 39 #include <Debug.h> 40 41 using namespace std; 42 43 __USE_CORTEX_NAMESPACE 44 45 // -------------------------------------------------------- // 46 // expat hooks 47 // -------------------------------------------------------- // 48 49 void _oc_handle_start( 50 void* pUser, 51 const XML_Char* pName, 52 const XML_Char** ppAtts) { 53 ((Importer*)pUser)->xmlElementStart(pName, ppAtts); 54 } 55 56 void _oc_handle_end( 57 void* pUser, 58 const XML_Char* pName) { 59 ((Importer*)pUser)->xmlElementEnd(pName); 60 } 61 62 void _oc_handle_pi( 63 void* pUser, 64 const XML_Char* pTarget, 65 const XML_Char* pData) { 66 ((Importer*)pUser)->xmlProcessingInstruction(pTarget, pData); 67 } 68 69 void _oc_handle_char( 70 void* pUser, 71 const XML_Char* pData, 72 int length) { 73 ((Importer*)pUser)->xmlCharacterData(pData, length); 74 } 75 76 void _oc_handle_default( 77 void* pUser, 78 const XML_Char* pData, 79 int length) { 80 ((Importer*)pUser)->xmlDefaultData(pData, length); 81 } 82 83 // -------------------------------------------------------- // 84 // ctor/dtor 85 // -------------------------------------------------------- // 86 87 Importer::~Importer() { 88 // clean up 89 freeParser(); 90 91 delete m_context; 92 } 93 94 95 Importer::Importer( 96 list<BString>& errors) : 97 98 m_parser(0), 99 m_docType(0), 100 m_identify(false), 101 m_context(new ImportContext(errors)), 102 m_rootObject(0) { 103 104 initParser(); 105 } 106 107 Importer::Importer( 108 ImportContext* context) : 109 110 m_parser(0), 111 m_docType(0), 112 m_identify(false), 113 m_context(context), 114 m_rootObject(0) { 115 116 ASSERT(m_context); 117 118 initParser(); 119 } 120 121 Importer::Importer( 122 list<BString>& errors, 123 IPersistent* rootObject, 124 XML::DocumentType* docType) : 125 126 m_parser(0), 127 m_docType(docType), 128 m_identify(false), 129 m_context(new ImportContext(errors)), 130 m_rootObject(rootObject) { 131 132 ASSERT(rootObject); 133 ASSERT(docType); 134 135 initParser(); 136 } 137 138 Importer::Importer( 139 ImportContext* context, 140 IPersistent* rootObject, 141 XML::DocumentType* docType) : 142 143 m_parser(0), 144 m_docType(docType), 145 m_identify(false), 146 m_context(context), 147 m_rootObject(rootObject) { 148 149 ASSERT(m_context); 150 ASSERT(rootObject); 151 ASSERT(docType); 152 153 initParser(); 154 } 155 156 // -------------------------------------------------------- // 157 // accessors 158 // -------------------------------------------------------- // 159 160 // the import context 161 const ImportContext& Importer::context() const { 162 return *m_context; 163 } 164 165 // matched (or provided) document type 166 XML::DocumentType* Importer::docType() const { 167 return m_docType; 168 } 169 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; 175 } 176 177 // -------------------------------------------------------- // 178 // operations 179 // -------------------------------------------------------- // 180 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; 187 } 188 189 void Importer::reset() { 190 // doesn't forget document type from identify cycle! 191 192 m_identify = false; 193 m_context->reset(); 194 m_rootObject = 0; 195 } 196 197 // handle a buffer; return false if an error occurs 198 bool Importer::parseBuffer( 199 const char* pBuffer, 200 uint32 length, 201 bool last) { 202 203 ASSERT(m_parser); 204 205 int err = XML_Parse(m_parser, pBuffer, length, last); 206 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; 212 213 } else 214 return true; 215 } 216 217 // -------------------------------------------------------- // 218 // internal operations 219 // -------------------------------------------------------- // 220 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; 226 227 XML_SetElementHandler( 228 m_parser, 229 &_oc_handle_start, 230 &_oc_handle_end); 231 232 XML_SetProcessingInstructionHandler( 233 m_parser, 234 &_oc_handle_pi); 235 236 XML_SetCharacterDataHandler( 237 m_parser, 238 &_oc_handle_char); 239 240 XML_SetDefaultHandlerExpand( 241 m_parser, 242 &_oc_handle_default); 243 244 XML_SetUserData( 245 m_parser, 246 (void*)this); 247 } 248 249 // clean up the parser 250 void Importer::freeParser() { 251 ASSERT(m_parser); 252 XML_ParserFree(m_parser); 253 m_parser = 0; 254 } 255 256 // -------------------------------------------------------- // 257 // XML parser event hooks 258 // -------------------------------------------------------- // 259 260 void Importer::xmlElementStart( 261 const char* pName, 262 const char** ppAttributes) { 263 264 if(m_context->m_state != ImportContext::PARSING) 265 return; 266 267 IPersistent* target = 0; 268 269 if(!m_context->m_elementStack.size()) { 270 // this is the first element; identify or verify document type 271 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; 280 } 281 282 // target the provided root object 283 target = m_rootObject; 284 } 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)); 290 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; 299 } 300 301 if(m_identify) { 302 // end of identify cycle 303 m_context->m_state = ImportContext::COMPLETE; 304 return; 305 } 306 } 307 } 308 // at this point, there'd better be a valid document type 309 ASSERT(m_docType); 310 311 // push element name onto the stack 312 m_context->m_elementStack.push_back(pName); 313 314 // try to create an object for this element if necessary 315 if(!target) 316 target = m_docType->objectFor(pName); 317 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); 323 324 // error? bail 325 if(m_context->state() != ImportContext::PARSING) 326 return; 327 328 // walk attributes 329 while(*ppAttributes) { 330 target->xmlImportAttribute( 331 ppAttributes[0], 332 ppAttributes[1], 333 *m_context); 334 335 // error? bail 336 if(m_context->state() != ImportContext::PARSING) 337 return; 338 339 ppAttributes += 2; 340 } 341 } else { 342 // no object directly maps to this element; hand to 343 // the current focus object 344 345 ASSERT(m_context->m_objectStack.size()); 346 IPersistent* curObject = m_context->m_objectStack.back().second; 347 ASSERT(curObject); 348 349 curObject->xmlImportChildBegin( 350 pName, 351 *m_context); 352 353 // error? bail 354 if(m_context->state() != ImportContext::PARSING) 355 return; 356 357 // walk attributes 358 while(*ppAttributes) { 359 curObject->xmlImportChildAttribute( 360 ppAttributes[0], 361 ppAttributes[1], 362 *m_context); 363 364 // error? bail 365 if(m_context->state() != ImportContext::PARSING) 366 return; 367 368 ppAttributes += 2; 369 } 370 } 371 } 372 373 void Importer::xmlElementEnd( 374 const char* pName) { 375 376 if(m_context->m_state != ImportContext::PARSING) 377 return; 378 ASSERT(m_docType); 379 380 // PRINT(("Importer::xmlElementEnd(): %s\n", pName)); 381 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; 387 } 388 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; 394 } 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(); 399 } 400 401 if(pObject) { 402 // notify object that import is complete 403 pObject->xmlImportComplete( 404 *m_context); 405 406 // error? bail 407 if(m_context->state() != ImportContext::PARSING) 408 return; 409 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; 423 } 424 } 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); 430 431 curObject->xmlImportChildComplete( 432 pName, 433 *m_context); 434 } 435 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()); 439 } 440 441 void Importer::xmlProcessingInstruction( 442 const char* pTarget, 443 const char* pData) { 444 445 if(m_context->m_state != ImportContext::PARSING) 446 return; 447 // PRINT(("Importer::xmlProcessingInstruction(): %s, %s\n", 448 // pTarget, pData)); 449 450 } 451 452 // not 0-terminated 453 void Importer::xmlCharacterData( 454 const char* pData, 455 int32 length) { 456 457 if(m_context->m_state != ImportContext::PARSING) 458 return; 459 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; 465 } 466 467 pObject = m_context->m_objectStack.back().second; 468 if(m_context->m_objectStack.back().first == m_context->element()) { 469 470 pObject->xmlImportContent( 471 pData, 472 length, 473 *m_context); 474 } 475 else { 476 pObject->xmlImportChildContent( 477 pData, 478 length, 479 *m_context); 480 } 481 } 482 483 // not 0-terminated 484 void Importer::xmlDefaultData( 485 const char* pData, 486 int32 length) { 487 488 if(m_context->m_state != ImportContext::PARSING) 489 return; 490 // PRINT(("Importer::xmlDefaultData()\n")); 491 } 492 493 // END -- Importer.cpp -- 494