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