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