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