1 // Importer.cpp 2 // e.moon 28jun99 3 4 #include "Importer.h" 5 #include <stdexcept> 6 7 #include <Autolock.h> 8 #include <Debug.h> 9 10 __USE_CORTEX_NAMESPACE 11 12 // -------------------------------------------------------- // 13 // expat hooks 14 // -------------------------------------------------------- // 15 16 void _oc_handle_start( 17 void* pUser, 18 const XML_Char* pName, 19 const XML_Char** ppAtts) { 20 ((Importer*)pUser)->xmlElementStart(pName, ppAtts); 21 } 22 23 void _oc_handle_end( 24 void* pUser, 25 const XML_Char* pName) { 26 ((Importer*)pUser)->xmlElementEnd(pName); 27 } 28 29 void _oc_handle_pi( 30 void* pUser, 31 const XML_Char* pTarget, 32 const XML_Char* pData) { 33 ((Importer*)pUser)->xmlProcessingInstruction(pTarget, pData); 34 } 35 36 void _oc_handle_char( 37 void* pUser, 38 const XML_Char* pData, 39 int length) { 40 ((Importer*)pUser)->xmlCharacterData(pData, length); 41 } 42 43 void _oc_handle_default( 44 void* pUser, 45 const XML_Char* pData, 46 int length) { 47 ((Importer*)pUser)->xmlDefaultData(pData, length); 48 } 49 50 // -------------------------------------------------------- // 51 // ctor/dtor 52 // -------------------------------------------------------- // 53 54 Importer::~Importer() { 55 // clean up 56 freeParser(); 57 58 delete m_context; 59 } 60 61 62 Importer::Importer( 63 list<BString>& errors) : 64 65 m_parser(0), 66 m_docType(0), 67 m_identify(false), 68 m_context(new ImportContext(errors)), 69 m_rootObject(0) { 70 71 initParser(); 72 } 73 74 Importer::Importer( 75 ImportContext* context) : 76 77 m_parser(0), 78 m_docType(0), 79 m_identify(false), 80 m_context(context), 81 m_rootObject(0) { 82 83 ASSERT(m_context); 84 85 initParser(); 86 } 87 88 Importer::Importer( 89 list<BString>& errors, 90 IPersistent* rootObject, 91 XML::DocumentType* docType) : 92 93 m_parser(0), 94 m_docType(docType), 95 m_identify(false), 96 m_context(new ImportContext(errors)), 97 m_rootObject(rootObject) { 98 99 ASSERT(rootObject); 100 ASSERT(docType); 101 102 initParser(); 103 } 104 105 Importer::Importer( 106 ImportContext* context, 107 IPersistent* rootObject, 108 XML::DocumentType* docType) : 109 110 m_parser(0), 111 m_docType(docType), 112 m_identify(false), 113 m_context(context), 114 m_rootObject(rootObject) { 115 116 ASSERT(m_context); 117 ASSERT(rootObject); 118 ASSERT(docType); 119 120 initParser(); 121 } 122 123 // -------------------------------------------------------- // 124 // accessors 125 // -------------------------------------------------------- // 126 127 // the import context 128 const ImportContext& Importer::context() const { 129 return *m_context; 130 } 131 132 // matched (or provided) document type 133 XML::DocumentType* Importer::docType() const { 134 return m_docType; 135 } 136 137 // completed object (available if 138 // context().state() == ImportContext::COMPLETE, or 139 // if a root object was provided to the ctor) 140 IPersistent* Importer::target() const { 141 return m_rootObject; 142 } 143 144 // -------------------------------------------------------- // 145 // operations 146 // -------------------------------------------------------- // 147 148 // put the importer into 'identify mode' 149 // (disengaged once the first element is encountered) 150 void Importer::setIdentifyMode() { 151 reset(); 152 m_docType = 0; 153 m_identify = true; 154 } 155 156 void Importer::reset() { 157 // doesn't forget document type from identify cycle! 158 159 m_identify = false; 160 m_context->reset(); 161 m_rootObject = 0; 162 } 163 164 // handle a buffer; return false if an error occurs 165 bool Importer::parseBuffer( 166 const char* pBuffer, 167 uint32 length, 168 bool last) { 169 170 ASSERT(m_parser); 171 172 int err = XML_Parse(m_parser, pBuffer, length, last); 173 174 if(!err) { 175 BString str = "Parse Error: "; 176 str << XML_ErrorString(XML_GetErrorCode(m_parser)); 177 m_context->reportError(str.String()); 178 return false; 179 180 } else 181 return true; 182 } 183 184 // -------------------------------------------------------- // 185 // internal operations 186 // -------------------------------------------------------- // 187 188 // create & initialize parser 189 void Importer::initParser() { 190 ASSERT(!m_parser); 191 m_parser = XML_ParserCreate(0); 192 m_context->m_pParser = m_parser; 193 194 XML_SetElementHandler( 195 m_parser, 196 &_oc_handle_start, 197 &_oc_handle_end); 198 199 XML_SetProcessingInstructionHandler( 200 m_parser, 201 &_oc_handle_pi); 202 203 XML_SetCharacterDataHandler( 204 m_parser, 205 &_oc_handle_char); 206 207 XML_SetDefaultHandlerExpand( 208 m_parser, 209 &_oc_handle_default); 210 211 XML_SetUserData( 212 m_parser, 213 (void*)this); 214 } 215 216 // clean up the parser 217 void Importer::freeParser() { 218 ASSERT(m_parser); 219 XML_ParserFree(m_parser); 220 m_parser = 0; 221 } 222 223 // -------------------------------------------------------- // 224 // XML parser event hooks 225 // -------------------------------------------------------- // 226 227 void Importer::xmlElementStart( 228 const char* pName, 229 const char** ppAttributes) { 230 231 if(m_context->m_state != ImportContext::PARSING) 232 return; 233 234 IPersistent* target = 0; 235 236 if(!m_context->m_elementStack.size()) { 237 // this is the first element; identify or verify document type 238 239 if(m_rootObject) { 240 // test against expected document type 241 ASSERT(m_docType); 242 if(m_docType->rootElement != pName) { 243 BString err("Unexpected document element (should be <"); 244 err << m_docType->rootElement << "/>"; 245 m_context->reportError(err.String()); 246 return; 247 } 248 249 // target the provided root object 250 target = m_rootObject; 251 } 252 else { 253 // look up doc type 254 BAutolock _l(XML::s_docTypeLock); 255 XML::doc_type_map::iterator it = XML::s_docTypeMap.find( 256 BString(pName)); 257 258 if(it != XML::s_docTypeMap.end()) 259 m_docType = (*it).second; 260 else { 261 // whoops, don't know how to handle this element: 262 BString err("No document type registered for element '"); 263 err << pName << "'."; 264 m_context->reportError(err.String()); 265 return; 266 } 267 268 if(m_identify) { 269 // end of identify cycle 270 m_context->m_state = ImportContext::COMPLETE; 271 return; 272 } 273 } 274 } 275 // at this point, there'd better be a valid document type 276 ASSERT(m_docType); 277 278 // push element name onto the stack 279 m_context->m_elementStack.push_back(pName); 280 281 // try to create an object for this element if necessary 282 if(!target) 283 target = m_docType->objectFor(pName); 284 285 if(target) { 286 // call 'begin import' hook 287 m_context->m_objectStack.push_back( 288 make_pair(m_context->element(), target)); 289 target->xmlImportBegin(*m_context); 290 291 // error? bail 292 if(m_context->state() != ImportContext::PARSING) 293 return; 294 295 // walk attributes 296 while(*ppAttributes) { 297 target->xmlImportAttribute( 298 ppAttributes[0], 299 ppAttributes[1], 300 *m_context); 301 302 // error? bail 303 if(m_context->state() != ImportContext::PARSING) 304 return; 305 306 ppAttributes += 2; 307 } 308 } else { 309 // no object directly maps to this element; hand to 310 // the current focus object 311 312 ASSERT(m_context->m_objectStack.size()); 313 IPersistent* curObject = m_context->m_objectStack.back().second; 314 ASSERT(curObject); 315 316 curObject->xmlImportChildBegin( 317 pName, 318 *m_context); 319 320 // error? bail 321 if(m_context->state() != ImportContext::PARSING) 322 return; 323 324 // walk attributes 325 while(*ppAttributes) { 326 curObject->xmlImportChildAttribute( 327 ppAttributes[0], 328 ppAttributes[1], 329 *m_context); 330 331 // error? bail 332 if(m_context->state() != ImportContext::PARSING) 333 return; 334 335 ppAttributes += 2; 336 } 337 } 338 } 339 340 void Importer::xmlElementEnd( 341 const char* pName) { 342 343 if(m_context->m_state != ImportContext::PARSING) 344 return; 345 ASSERT(m_docType); 346 347 // PRINT(("Importer::xmlElementEnd(): %s\n", pName)); 348 349 // compare name to element on top of stack 350 if(!m_context->m_elementStack.size() || 351 m_context->m_elementStack.back() != pName) { 352 m_context->reportError("Mismatched end tag."); 353 return; 354 } 355 356 // see if it matches the topmost object 357 IPersistent* pObject = 0; 358 if(!m_context->m_objectStack.size()) { 359 m_context->reportError("No object being constructed."); 360 return; 361 } 362 if(m_context->m_objectStack.back().first == m_context->element()) { 363 // matched; pop it 364 pObject = m_context->m_objectStack.back().second; 365 m_context->m_objectStack.pop_back(); 366 } 367 368 if(pObject) { 369 // notify object that import is complete 370 pObject->xmlImportComplete( 371 *m_context); 372 373 // error? bail 374 if(m_context->state() != ImportContext::PARSING) 375 return; 376 377 if(m_context->m_objectStack.size()) { 378 // hand the newly-constructed child to its parent 379 m_context->m_objectStack.back().second->xmlImportChild( 380 pObject, 381 *m_context); 382 } else { 383 // done 384 ASSERT(m_context->m_elementStack.size() == 1); 385 m_context->m_state = ImportContext::COMPLETE; 386 if(m_rootObject) { 387 ASSERT(m_rootObject == pObject); 388 } else 389 m_rootObject = pObject; 390 } 391 } 392 else { 393 // notify current topmost object 394 ASSERT(m_context->m_objectStack.size()); 395 IPersistent* curObject = m_context->m_objectStack.back().second; 396 ASSERT(curObject); 397 398 curObject->xmlImportChildComplete( 399 pName, 400 *m_context); 401 } 402 403 // remove entry from element stack 404 m_context->m_elementStack.pop_back(); 405 ASSERT(m_context->m_objectStack.size() <= m_context->m_elementStack.size()); 406 } 407 408 void Importer::xmlProcessingInstruction( 409 const char* pTarget, 410 const char* pData) { 411 412 if(m_context->m_state != ImportContext::PARSING) 413 return; 414 // PRINT(("Importer::xmlProcessingInstruction(): %s, %s\n", 415 // pTarget, pData)); 416 417 } 418 419 // not 0-terminated 420 void Importer::xmlCharacterData( 421 const char* pData, 422 int32 length) { 423 424 if(m_context->m_state != ImportContext::PARSING) 425 return; 426 427 // see if the current element matches the topmost object 428 IPersistent* pObject = 0; 429 if(!m_context->m_objectStack.size()) { 430 m_context->reportError("No object being constructed."); 431 return; 432 } 433 434 pObject = m_context->m_objectStack.back().second; 435 if(m_context->m_objectStack.back().first == m_context->element()) { 436 437 pObject->xmlImportContent( 438 pData, 439 length, 440 *m_context); 441 } 442 else { 443 pObject->xmlImportChildContent( 444 pData, 445 length, 446 *m_context); 447 } 448 } 449 450 // not 0-terminated 451 void Importer::xmlDefaultData( 452 const char* pData, 453 int32 length) { 454 455 if(m_context->m_state != ImportContext::PARSING) 456 return; 457 // PRINT(("Importer::xmlDefaultData()\n")); 458 } 459 460 // END -- Importer.cpp -- 461