1 // XML.cpp 2 // e.moon 1jul99 3 4 #include "XML.h" 5 #include "Importer.h" 6 7 #include <Autolock.h> 8 #include <Debug.h> 9 10 #include "array_delete.h" 11 #include "set_tools.h" 12 13 using namespace std; 14 15 __USE_CORTEX_NAMESPACE 16 17 // -------------------------------------------------------- // 18 // static members 19 // -------------------------------------------------------- // 20 21 XML::doc_type_map XML::s_docTypeMap; 22 BLocker XML::s_docTypeLock("XML::s_docTypeLock"); 23 24 const BMimeType XML::DocumentType::s_defaultMimeType("text/xml"); 25 26 // -------------------------------------------------------- // 27 // document type operations 28 // -------------------------------------------------------- // 29 30 // takes responsibility for the given type object 31 32 /*static*/ 33 void XML::AddDocumentType( 34 XML::DocumentType* type) { 35 36 ASSERT(type); 37 BAutolock _l(s_docTypeLock); 38 39 // s_docTypeMap.insert( 40 // make_pair(type->rootElement, type)); 41 s_docTypeMap.insert( 42 pair<const BString, XML::DocumentType*>(type->rootElement, type)); 43 } 44 45 // -------------------------------------------------------- // 46 // import/export operations 47 // -------------------------------------------------------- // 48 49 // identify object in stream 50 // returns: 51 // - B_OK on success, or 52 // - B_BAD_TYPE if no document type matches the root 53 // element of the stream, or 54 // - B_IO_ERROR if the document is malformed, or if a 55 // read error occurs. 56 57 /*static*/ 58 status_t XML::Identify( 59 BDataIO* stream, 60 DocumentType** outType, 61 list<BString>* outErrors) { 62 63 ASSERT(stream); 64 65 // prepare the input buffer 66 const uint32 bufferSize = 4096; 67 char* buffer = new char[bufferSize]; 68 array_delete<char> _d(buffer); 69 70 // prepare an Importer to figure document type (from first element) 71 Importer i(*outErrors); 72 i.setIdentifyMode(); 73 74 while( 75 i.context().state() == ImportContext::PARSING) { 76 77 // read chunk (no 0 terminator) 78 ssize_t readCount = stream->Read(buffer, bufferSize); 79 if(readCount == 0) 80 // done 81 break; 82 else if(readCount < 0) { 83 // error 84 BString err = "Read error: '"; 85 err << strerror(readCount) << "'; ABORTING."; 86 outErrors->push_back(err); 87 88 return B_IO_ERROR; 89 } 90 91 // feed to parser 92 if(!i.parseBuffer( 93 buffer, readCount, !stream)) { 94 break; 95 } 96 } 97 98 // return found type 99 if(i.docType()) { 100 *outType = i.docType(); 101 return B_OK; 102 } 103 else return B_BAD_TYPE; 104 } 105 106 // read the root object from the given stream 107 108 /*static*/ 109 status_t XML::Read( 110 BDataIO* stream, 111 IPersistent** outObject, 112 list<BString>* outErrors) { 113 114 Importer i(*outErrors); 115 status_t err = _DoRead(stream, i, outErrors); 116 if(err == B_OK) { 117 // return completed object 118 ASSERT(i.target()); 119 *outObject = i.target(); 120 } 121 return err; 122 } 123 124 /*static*/ 125 status_t XML::Read( 126 BDataIO* stream, 127 IPersistent** outObject, 128 ImportContext* context) { 129 130 Importer i(context); 131 status_t err = _DoRead(stream, i, &context->errors()); 132 if(err == B_OK) { 133 // return completed object 134 ASSERT(i.target()); 135 *outObject = i.target(); 136 } 137 return err; 138 } 139 140 // [e.moon 26nov99] 141 // populate the provided root object from the given 142 // XML stream. you need to give the expected root 143 // (document) element name corresponding to the 144 // item you provide. 145 // returns: 146 // - B_OK on success, or 147 // - B_IO_ERROR if the document is malformed, or if a 148 // read error occurs, or 149 // - B_ERROR 150 151 /*static*/ 152 status_t XML::Read( 153 BDataIO* stream, 154 IPersistent* rootObject, 155 XML::DocumentType* documentType, 156 list<BString>* outErrors) { 157 158 Importer i(*outErrors, rootObject, documentType); 159 return _DoRead(stream, i, outErrors); 160 } 161 162 /*static*/ 163 status_t XML::Read( 164 BDataIO* stream, 165 IPersistent* rootObject, 166 XML::DocumentType* documentType, 167 ImportContext* context) { 168 169 Importer i(context, rootObject, documentType); 170 return _DoRead(stream, i, &context->errors()); 171 } 172 173 /*static*/ 174 status_t XML::_DoRead( 175 BDataIO* stream, 176 Importer& i, 177 list<BString>* outErrors) { 178 179 // prepare the input buffer 180 const uint32 bufferSize = 4096; 181 char* buffer = new char[bufferSize]; 182 array_delete<char> _d(buffer); 183 184 while( 185 i.context().state() == ImportContext::PARSING) { 186 187 // read chunk (no 0 terminator) 188 ssize_t readCount = stream->Read(buffer, bufferSize); 189 if(readCount == 0) 190 // done 191 break; 192 else if(readCount < 0) { 193 // error 194 BString err = "Read error: '"; 195 err << strerror(readCount) << "'; ABORTING."; 196 outErrors->push_back(err); 197 return B_IO_ERROR; 198 } 199 200 // feed to parser 201 if(!i.parseBuffer( 202 buffer, readCount, !stream)) { 203 break; 204 } 205 } 206 207 status_t err = B_ERROR; 208 if(i.context().state() == ImportContext::COMPLETE) 209 err = B_OK; 210 211 // clean up 212 return err; 213 } 214 215 // write the given object to the given stream 216 217 /*static*/ 218 status_t XML::Write( 219 BDataIO* stream, 220 IPersistent* object, 221 BString* outError) { 222 223 ASSERT(object); 224 225 ExportContext context(stream); 226 status_t err = context.writeObject(object); 227 if(err < B_OK) 228 *outError = context.errorText(); 229 return err; 230 } 231 232 // -------------------------------------------------------- // 233 // XML::DocumentType 234 // -------------------------------------------------------- // 235 236 class _NullMapping : public XMLElementMapping { 237 public: 238 _NullMapping( 239 const char* _element) : 240 XMLElementMapping(_element) {} 241 242 IPersistent* create() const { return 0; } 243 }; 244 245 XML::DocumentType::~DocumentType() { 246 // clean up 247 ptr_set_delete(m_mappingSet.begin(), m_mappingSet.end()); 248 } 249 250 XML::DocumentType::DocumentType( 251 const char* _rootElement, 252 const char* _mimeType) : 253 rootElement(_rootElement), 254 mimeType(_mimeType ? _mimeType : s_defaultMimeType.Type()) {} 255 256 // *** 'factory' interface 257 258 // The DocumentType takes ownership of the given mapping 259 // object. If a mapping for the element already exists, 260 // the provided object is deleted and the method returns 261 // B_NAME_IN_USE. 262 status_t XML::DocumentType::addMapping( 263 XMLElementMapping* mapping) { 264 265 pair<mapping_set::iterator, bool> ret = m_mappingSet.insert(mapping); 266 if(!ret.second) { 267 delete mapping; 268 return B_NAME_IN_USE; 269 } else 270 return B_OK; 271 } 272 273 IPersistent* XML::DocumentType::objectFor( 274 const char* element) { 275 276 _NullMapping m(element); 277 mapping_set::iterator it = m_mappingSet.find(&m); 278 279 return (it != m_mappingSet.end()) ? 280 (*it)->create() : 0; 281 } 282 283 // END -- XML.cpp -- 284