/* * libSpiff - XSPF playlist handling library * * Copyright (C) 2007, Sebastian Pipping / Xiph.Org Foundation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * * 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. * * * Neither the name of the Xiph.Org Foundation nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS 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. * * Sebastian Pipping, sping@xiph.org */ /** * @file SpiffData.cpp * Implementation of SpiffData. */ #include #include #include using namespace Spiff::Toolbox; using namespace std; namespace Spiff { /// @cond DOXYGEN_NON_API /** * D object for SpiffData. */ class SpiffDataPrivate { friend class SpiffData; const XML_Char * image; ///< Image URI const XML_Char * info; ///< Info URI const XML_Char * annotation; ///< Annotation const XML_Char * creator; ///< Creator/artist const XML_Char * title; ///< Title bool ownImage; ///< Image memory ownership flag bool ownInfo; ///< Info memory ownership flag bool ownAnnotation; ///< Annotation memory ownership flag bool ownCreator; ///< Creator memory ownership flag bool ownTitle; ///< Title memory ownership flag std::deque *, std::pair *> *> * links; ///< List of link pairs std::deque *, std::pair *> *> * metas; ///< List of meta pairs std::deque *> * extensions; ///< List of extensions /** * Creates a new D object. */ SpiffDataPrivate() : image(NULL), info(NULL), annotation(NULL), creator(NULL), title(NULL), ownImage(false), ownInfo(false), ownAnnotation(false), ownCreator(false), ownTitle(false), links(NULL), metas(NULL), extensions(NULL) { } /** * Copy constructor. * * @param source Source to copy from */ SpiffDataPrivate(const SpiffDataPrivate & source) : image(source.ownImage ? newAndCopy(source.image) : source.image), info(source.ownInfo ? newAndCopy(source.info) : source.info), annotation(source.ownAnnotation ? newAndCopy(source.annotation) : source.annotation), creator(source.ownCreator ? newAndCopy(source.creator) : source.creator), title(source.ownTitle ? newAndCopy(source.title) : source.title), ownImage(source.ownImage), ownInfo(source.ownInfo), ownAnnotation(source.ownAnnotation), ownCreator(source.ownCreator), ownTitle(source.ownTitle), links(NULL), metas(NULL), extensions(NULL) { copyMetasOrLinks(this->links, source.links); copyMetasOrLinks(this->metas, source.metas); copyExtensions(this->extensions, source.extensions); } /** * Assignment operator. * * @param source Source to copy from */ SpiffDataPrivate & operator=(const SpiffDataPrivate & source) { if (this != &source) { free(); copyIfOwned(this->title, this->ownTitle, source.title, source.ownTitle); copyIfOwned(this->creator, this->ownCreator, source.creator, source.ownCreator); copyIfOwned(this->annotation, this->ownAnnotation, source.annotation, source.ownAnnotation); copyIfOwned(this->image, this->ownImage, source.image, source.ownImage); copyIfOwned(this->info, this->ownInfo, source.info, source.ownInfo); copyMetasOrLinks(this->links, source.links); copyMetasOrLinks(this->metas, source.metas); copyExtensions(this->extensions, source.extensions); } return *this; } /** * Destroys this D object. */ ~SpiffDataPrivate() { free(); } void free() { freeIfOwned(this->title, this->ownTitle); freeIfOwned(this->creator, this->ownCreator); freeIfOwned(this->annotation, this->ownAnnotation); freeIfOwned(this->image, this->ownImage); freeIfOwned(this->info, this->ownInfo); freeMetasOrLinks(this->links); freeMetasOrLinks(this->metas); freeExtensions(this->extensions); } static inline void freeMetasOrLinks(std::deque *, std::pair *> *> * & container) { if (container != NULL) { deque *, pair *> *> ::const_iterator iter = container->begin(); while (iter != container->end()) { pair *, pair *> * const entry = *iter; if (entry->first->second) { delete [] entry->first->first; } delete entry->first; if (entry->second->second) { delete [] entry->second->first; } delete entry->second; delete entry; iter++; } container->clear(); delete container; container = NULL; } } static inline void copyMetasOrLinks(std::deque *, std::pair *> *> * & dest, std::deque *, std::pair *> *> * const & source) { dest = new deque *, pair *> *>(); if (source != NULL) { deque *, pair *> *>::const_iterator iter = source->begin(); while (iter != source->end()) { const pair *, pair *> * const entry = *iter; const bool ownRel = entry->first->second; const bool ownContent = entry->second->second; const XML_Char * const rel = ownRel ? entry->first->first : Toolbox::newAndCopy(entry->first->first); const XML_Char * const content = ownContent ? entry->second->first : Toolbox::newAndCopy(entry->second->first); SpiffData::appendHelper(dest, rel, ownRel, content, ownContent); iter++; } } } static inline void freeExtensions(std::deque *> * & container) { if (container != NULL) { deque *>::const_iterator iter = container->begin(); while (iter != container->end()) { pair * const entry = *iter; if (entry->second) { delete entry->first; } delete entry; iter++; } container->clear(); delete container; container = NULL; } } static inline void copyExtensions(std::deque< std::pair *> * & dest, std::deque< std::pair *> * const & source) { dest = new deque *>(); if (source != NULL) { deque *>::const_iterator iter = source->begin(); while (iter != source->end()) { const pair * const entry = *iter; const bool own = entry->second; const SpiffExtension * const extension = own ? entry->first->clone() : entry->first; SpiffData::appendHelper(dest, extension, own); iter++; } } } }; /// @endcond SpiffData::SpiffData() : d(new SpiffDataPrivate()) { // NOOP } SpiffData::SpiffData(const SpiffData & source) : d(new SpiffDataPrivate(*(source.d))) { // NOOP } SpiffData & SpiffData::operator=(const SpiffData & source) { if (this != &source) { *(this->d) = *(source.d); } return *this; } SpiffData::~SpiffData() { delete this->d; } void SpiffData::giveAnnotation(const XML_Char * annotation, bool copy) { Toolbox::deleteNewAndCopy(this->d->annotation, this->d->ownAnnotation, annotation, copy); } void SpiffData::giveCreator(const XML_Char * creator, bool copy) { Toolbox::deleteNewAndCopy(this->d->creator, this->d->ownCreator, creator, copy); } void SpiffData::giveInfo(const XML_Char * info, bool copy) { Toolbox::deleteNewAndCopy(this->d->info, this->d->ownInfo, info, copy); } void SpiffData::giveImage(const XML_Char * image, bool copy) { Toolbox::deleteNewAndCopy(this->d->image, this->d->ownImage, image, copy); } void SpiffData::giveTitle(const XML_Char * title, bool copy) { Toolbox::deleteNewAndCopy(this->d->title, this->d->ownTitle, title, copy); } void SpiffData::giveAppendLink(const XML_Char * rel, bool copyRel, const XML_Char * content, bool copyContent) { appendHelper(this->d->links, copyRel ? Toolbox::newAndCopy(rel) : rel, true, copyContent ? Toolbox::newAndCopy(content) : content, true); } void SpiffData::giveAppendMeta(const XML_Char * rel, bool copyRel, const XML_Char * content, bool copyContent) { appendHelper(this->d->metas, copyRel ? Toolbox::newAndCopy(rel) : rel, true, copyContent ? Toolbox::newAndCopy(content) : content, true); } void SpiffData::giveAppendExtension(const SpiffExtension * extension, bool copy) { appendHelper(this->d->extensions, copy ? extension->clone() : extension, true); } void SpiffData::lendAnnotation(const XML_Char * annotation) { Toolbox::deleteNewAndCopy(this->d->annotation, this->d->ownAnnotation, annotation, false); } void SpiffData::lendCreator(const XML_Char * creator) { Toolbox::deleteNewAndCopy(this->d->creator, this->d->ownCreator, creator, false); } void SpiffData::lendInfo(const XML_Char * info) { Toolbox::deleteNewAndCopy(this->d->info, this->d->ownInfo, info, false); } void SpiffData::lendImage(const XML_Char * image) { Toolbox::deleteNewAndCopy(this->d->image, this->d->ownImage, image, false); } void SpiffData::lendTitle(const XML_Char * title) { Toolbox::deleteNewAndCopy(this->d->title, this->d->ownTitle, title, false); } void SpiffData::lendAppendLink(const XML_Char * rel, const XML_Char * content) { appendHelper(this->d->links, rel, false, content, false); } void SpiffData::lendAppendMeta(const XML_Char * rel, const XML_Char * content) { appendHelper(this->d->metas, rel, false, content, false); } void SpiffData::lendAppendExtension(SpiffExtension * extension) { appendHelper(this->d->extensions, extension, false); } XML_Char * SpiffData::stealTitle() { return stealHelper(this->d->title, this->d->ownTitle); } XML_Char * SpiffData::stealAnnotation() { return stealHelper(this->d->annotation, this->d->ownAnnotation); } XML_Char * SpiffData::stealCreator() { return stealHelper(this->d->creator, this->d->ownCreator); } XML_Char * SpiffData::stealInfo() { return stealHelper(this->d->info, this->d->ownInfo); } XML_Char * SpiffData::stealImage() { return stealHelper(this->d->image, this->d->ownImage); } pair * SpiffData::stealFirstMeta() { return stealFirstHelper(this->d->metas); } pair * SpiffData::stealFirstLink() { return stealFirstHelper(this->d->links); } SpiffExtension * SpiffData::stealFirstExtension() { return stealFirstHelper(this->d->extensions); } const XML_Char * SpiffData::getImage() const { return this->d->image; } const XML_Char * SpiffData::getInfo() const { return this->d->info; } const XML_Char * SpiffData::getAnnotation() const { return this->d->annotation; } const XML_Char * SpiffData::getCreator() const { return this->d->creator; } const XML_Char * SpiffData::getTitle() const { return this->d->title; } pair * SpiffData::getLink(int index) const { return getHelper(this->d->links, index); } pair * SpiffData::getMeta(int index) const { return getHelper(this->d->metas, index); } const SpiffExtension * SpiffData::getExtension(int index) const { return getHelper(this->d->extensions, index); } int SpiffData::getLinkCount() const { return (this->d->links == NULL) ? 0 : static_cast(this->d->links->size()); } int SpiffData::getMetaCount() const { return (this->d->metas == NULL) ? 0 : static_cast(this->d->metas->size()); } int SpiffData::getExtensionCount() const { return (this->d->extensions == NULL) ? 0 : static_cast(this->d->extensions->size()); } /*static*/ void SpiffData::appendHelper( std::deque *, std::pair *> *> * & container, const XML_Char * rel, bool ownRel, const XML_Char * content, bool ownContent) { if (container == NULL) { container = new deque *, pair *> *>; } pair * const first = new pair(rel, ownRel); pair * const second = new pair(content, ownContent); pair *, pair *> * const entry = new pair *, pair *>(first, second); container->push_back(entry); } /*static*/ void SpiffData::appendHelper( std::deque *> * & container, const SpiffExtension * extension, bool own) { if (container == NULL) { container = new deque *>; } pair * const entry = new pair(extension, own); container->push_back(entry); } /*static*/ XML_Char * SpiffData::stealHelper(const XML_Char * & property, bool own) { const XML_Char * const res = Toolbox::getSetNull(property); if (own) { return const_cast(res); } else if (res == NULL) { return NULL; } else { return Toolbox::newAndCopy(res); } } /*static*/ pair * SpiffData::stealFirstHelper( std::deque *, std::pair *> *> * & container) { if ((container == NULL) || container->empty()) { return NULL; } pair *, pair *> * const entry = container->front(); container->pop_front(); pair * const res = new pair( entry->first->second ? const_cast(entry->first->first) : Toolbox::newAndCopy(entry->first->first), entry->second->second ? const_cast(entry->second->first) : Toolbox::newAndCopy(entry->second->first)); delete entry->first; delete entry->second; delete entry; return res; } /*static*/ SpiffExtension * SpiffData::stealFirstHelper( std::deque *> * & container) { if ((container == NULL) || container->empty()) { return NULL; } pair * const entry = container->front(); container->pop_front(); SpiffExtension * res = entry->second ? const_cast(entry->first) : entry->first->clone(); delete entry; return res; } /*static*/ pair * SpiffData::getHelper( std::deque *, std::pair *> *> * & container, int index) { if ((container == NULL) || container->empty() || (index < 0) || (index >= static_cast(container->size()))) { return NULL; } pair *, pair *> * const entry = container->at(index); // NOTE: getX() just peeps at data so don't clone anything pair * const res = new pair( entry->first->first, entry->second->first); return res; } /*static*/ const SpiffExtension * SpiffData::getHelper( std::deque *> * & container, int index) { if ((container == NULL) || container->empty() || (index < 0) || (index >= static_cast(container->size()))) { return NULL; } // NOTE: getX() just peeps at data so don't clone anything pair * const entry = container->at(index); return entry->first; } }