/* * Copyright (c) 1999-2000, Eric Moon. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions, and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // XML.cpp // e.moon 1jul99 #include "XML.h" #include "Importer.h" #include #include #include "array_delete.h" #include "set_tools.h" using namespace std; __USE_CORTEX_NAMESPACE // -------------------------------------------------------- // // static members // -------------------------------------------------------- // XML::doc_type_map XML::s_docTypeMap; BLocker XML::s_docTypeLock("XML::s_docTypeLock"); const BMimeType XML::DocumentType::s_defaultMimeType("text/xml"); // -------------------------------------------------------- // // document type operations // -------------------------------------------------------- // // takes responsibility for the given type object /*static*/ void XML::AddDocumentType( XML::DocumentType* type) { ASSERT(type); BAutolock _l(s_docTypeLock); // s_docTypeMap.insert( // make_pair(type->rootElement, type)); s_docTypeMap.insert( pair(type->rootElement, type)); } // -------------------------------------------------------- // // import/export operations // -------------------------------------------------------- // // identify object in stream // returns: // - B_OK on success, or // - B_BAD_TYPE if no document type matches the root // element of the stream, or // - B_IO_ERROR if the document is malformed, or if a // read error occurs. /*static*/ status_t XML::Identify( BDataIO* stream, DocumentType** outType, list* outErrors) { ASSERT(stream); // prepare the input buffer const uint32 bufferSize = 4096; char* buffer = new char[bufferSize]; array_delete _d(buffer); // prepare an Importer to figure document type (from first element) Importer i(*outErrors); i.setIdentifyMode(); while( i.context().state() == ImportContext::PARSING) { // read chunk (no 0 terminator) ssize_t readCount = stream->Read(buffer, bufferSize); if(readCount == 0) // done break; else if(readCount < 0) { // error BString err = "Read error: '"; err << strerror(readCount) << "'; ABORTING."; outErrors->push_back(err); return B_IO_ERROR; } // feed to parser if(!i.parseBuffer( buffer, readCount, !stream)) { break; } } // return found type if(i.docType()) { *outType = i.docType(); return B_OK; } else return B_BAD_TYPE; } // read the root object from the given stream /*static*/ status_t XML::Read( BDataIO* stream, IPersistent** outObject, list* outErrors) { Importer i(*outErrors); status_t err = _DoRead(stream, i, outErrors); if(err == B_OK) { // return completed object ASSERT(i.target()); *outObject = i.target(); } return err; } /*static*/ status_t XML::Read( BDataIO* stream, IPersistent** outObject, ImportContext* context) { Importer i(context); status_t err = _DoRead(stream, i, &context->errors()); if(err == B_OK) { // return completed object ASSERT(i.target()); *outObject = i.target(); } return err; } // [e.moon 26nov99] // populate the provided root object from the given // XML stream. you need to give the expected root // (document) element name corresponding to the // item you provide. // returns: // - B_OK on success, or // - B_IO_ERROR if the document is malformed, or if a // read error occurs, or // - B_ERROR /*static*/ status_t XML::Read( BDataIO* stream, IPersistent* rootObject, XML::DocumentType* documentType, list* outErrors) { Importer i(*outErrors, rootObject, documentType); return _DoRead(stream, i, outErrors); } /*static*/ status_t XML::Read( BDataIO* stream, IPersistent* rootObject, XML::DocumentType* documentType, ImportContext* context) { Importer i(context, rootObject, documentType); return _DoRead(stream, i, &context->errors()); } /*static*/ status_t XML::_DoRead( BDataIO* stream, Importer& i, list* outErrors) { // prepare the input buffer const uint32 bufferSize = 4096; char* buffer = new char[bufferSize]; array_delete _d(buffer); while( i.context().state() == ImportContext::PARSING) { // read chunk (no 0 terminator) ssize_t readCount = stream->Read(buffer, bufferSize); if(readCount == 0) // done break; else if(readCount < 0) { // error BString err = "Read error: '"; err << strerror(readCount) << "'; ABORTING."; outErrors->push_back(err); return B_IO_ERROR; } // feed to parser if(!i.parseBuffer( buffer, readCount, !stream)) { break; } } status_t err = B_ERROR; if(i.context().state() == ImportContext::COMPLETE) err = B_OK; // clean up return err; } // write the given object to the given stream /*static*/ status_t XML::Write( BDataIO* stream, IPersistent* object, BString* outError) { ASSERT(object); ExportContext context(stream); status_t err = context.writeObject(object); if(err < B_OK) *outError = context.errorText(); return err; } // -------------------------------------------------------- // // XML::DocumentType // -------------------------------------------------------- // class _NullMapping : public XMLElementMapping { public: _NullMapping( const char* _element) : XMLElementMapping(_element) {} IPersistent* create() const { return 0; } }; XML::DocumentType::~DocumentType() { // clean up ptr_set_delete(m_mappingSet.begin(), m_mappingSet.end()); } XML::DocumentType::DocumentType( const char* _rootElement, const char* _mimeType) : rootElement(_rootElement), mimeType(_mimeType ? _mimeType : s_defaultMimeType.Type()) {} // *** 'factory' interface // The DocumentType takes ownership of the given mapping // object. If a mapping for the element already exists, // the provided object is deleted and the method returns // B_NAME_IN_USE. status_t XML::DocumentType::addMapping( XMLElementMapping* mapping) { pair ret = m_mappingSet.insert(mapping); if(!ret.second) { delete mapping; return B_NAME_IN_USE; } else return B_OK; } IPersistent* XML::DocumentType::objectFor( const char* element) { _NullMapping m(element); mapping_set::iterator it = m_mappingSet.find(&m); return (it != m_mappingSet.end()) ? (*it)->create() : 0; } // END -- XML.cpp --