/* * 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 SpiffProps.cpp * Implementation of SpiffProps. */ #include #include #include #include using namespace Spiff::Toolbox; using namespace std; namespace Spiff { /// @cond DOXYGEN_NON_API /** * D object for SpiffProps. */ class SpiffPropsPrivate { friend class SpiffProps; const XML_Char * location; ///< Location URI const XML_Char * license; ///< License URI const XML_Char * identifier; ///< Identifier URI bool ownLocation; ///< Location memory ownership flag bool ownLicense; ///< License memory ownership flag bool ownIdentifier; ///< Identifier memory ownership flag std::deque *> *> * attributions; ///< List of location and identifier URIs const SpiffDateTime * date; ///< Date bool ownDate; ///< Date memory ownership flag int version; ///< XSPF version /** * Creates a new D object. */ SpiffPropsPrivate() : location(NULL), license(NULL), identifier(NULL), ownLocation(false), ownLicense(false), ownIdentifier(false), attributions(NULL), date(NULL), ownDate(false), version(-1) { } /** * Copy constructor. * * @param source Source to copy from */ SpiffPropsPrivate(const SpiffPropsPrivate & source) : location(source.ownLocation ? Toolbox::newAndCopy(source.location) : source.location), license(source.ownLicense ? Toolbox::newAndCopy(source.license) : source.license), identifier(source.ownIdentifier ? Toolbox::newAndCopy(source.identifier) : source.identifier), ownLocation(source.ownLocation), ownLicense(source.ownLicense), ownIdentifier(source.ownIdentifier), attributions(NULL), // Created in appendHelper date(source.ownDate ? new SpiffDateTime(*(source.date)) : source.date), ownDate(source.ownDate), version(source.version) { if (source.attributions != NULL) { copyAttributions(this->attributions, source.attributions); } } /** * Assignment operator. * * @param source Source to copy from */ SpiffPropsPrivate & operator=(const SpiffPropsPrivate & source) { if (this != &source) { free(); assign(source); } return *this; } /** * Destroys this D object. */ ~SpiffPropsPrivate() { free(); } static void copyAttributions(std::deque *> *> * & dest, const std::deque *> *> * source) { deque *> *> ::const_iterator iter = source->begin(); while (iter != source->end()) { const pair *> * const entry = *iter; const XML_Char * const value = entry->second->first; const bool ownership = entry->second->second; const bool isLocation = entry->first; SpiffProps::appendHelper(dest, value, ownership, isLocation); iter++; } } void assign(const SpiffPropsPrivate & source) { // Assigns all members, does not free current content this->location = source.ownLocation ? Toolbox::newAndCopy(source.location) : source.location; this->license = source.ownLicense ? Toolbox::newAndCopy(source.license) : source.license; this->identifier = source.ownIdentifier ? Toolbox::newAndCopy(source.identifier) : source.identifier; this->ownLocation = source.ownLocation; this->ownLicense = source.ownLicense; this->ownIdentifier = source.ownIdentifier; this->attributions = NULL; // Created by appendHelper this->date = source.ownDate ? new SpiffDateTime(*(source.date)) : source.date; this->ownDate = source.ownDate; this->version = source.version; if (source.attributions != NULL) { copyAttributions(this->attributions, source.attributions); } } void free() { // Frees all data, does not set to NULL freeIfOwned(this->location, this->ownLocation); freeIfOwned(this->identifier, this->ownIdentifier); freeIfOwned(this->license, this->ownLicense); if (this->attributions != NULL) { deque *> *>::const_iterator iter = this->attributions->begin(); while (iter != this->attributions->end()) { pair *> * const entry = *iter; if (entry->second->second) { delete [] entry->second->first; } delete entry->second; delete entry; iter++; } delete this->attributions; this->attributions = NULL; } if (this->ownDate && (this->date != NULL)) { delete this->date; this->date = NULL; } } }; /// @endcond SpiffProps::SpiffProps() : SpiffData(), d(new SpiffPropsPrivate()) { } SpiffProps::SpiffProps(const SpiffProps & source) : SpiffData(source), d(new SpiffPropsPrivate(*(source.d))) { } SpiffProps & SpiffProps::operator=(const SpiffProps & source) { if (this != &source) { SpiffProps::operator=(source); *(this->d) = *(source.d); } return *this; } SpiffProps::~SpiffProps() { delete this->d; } void SpiffProps::giveLocation(const XML_Char * location, bool copy) { Toolbox::deleteNewAndCopy(this->d->location, this->d->ownLocation, location, copy); } void SpiffProps::giveLicense(const XML_Char * license, bool copy) { Toolbox::deleteNewAndCopy(this->d->license, this->d->ownLicense, license, copy); } void SpiffProps::giveIdentifier(const XML_Char * identifier, bool copy) { Toolbox::deleteNewAndCopy(this->d->identifier, this->d->ownIdentifier, identifier, copy); } void SpiffProps::giveAppendAttributionIdentifier(const XML_Char * identifier, bool copy) { appendHelper(this->d->attributions, copy ? Toolbox::newAndCopy(identifier) : identifier, true, false); } void SpiffProps::giveAppendAttributionLocation(const XML_Char * location, bool copy) { appendHelper(this->d->attributions, copy ? Toolbox::newAndCopy(location) : location, true, true); } void SpiffProps::giveDate(const SpiffDateTime * date, bool copy) { SpiffProps::deleteNewAndCopy(this->d->date, this->d->ownDate, date, copy); } void SpiffProps::lendLocation(const XML_Char * location) { Toolbox::deleteNewAndCopy(this->d->location, this->d->ownLocation, location, false); } void SpiffProps::lendLicense(const XML_Char * license) { Toolbox::deleteNewAndCopy(this->d->license, this->d->ownLicense, license, false); } void SpiffProps::lendIdentifier(const XML_Char * identifier) { Toolbox::deleteNewAndCopy(this->d->identifier, this->d->ownIdentifier, identifier, false); } void SpiffProps::lendAppendAttributionIdentifier(const XML_Char * identifier) { appendHelper(this->d->attributions, identifier, false, false); } void SpiffProps::lendAppendAttributionLocation(const XML_Char * location) { appendHelper(this->d->attributions, location, false, true); } void SpiffProps::lendDate(const SpiffDateTime * date) { SpiffProps::deleteNewAndCopy(this->d->date, this->d->ownDate, date, false); } XML_Char * SpiffProps::stealLocation() { return SpiffData::stealHelper(this->d->location, this->d->ownLocation); } XML_Char * SpiffProps::stealIdentifier() { return SpiffData::stealHelper(this->d->identifier, this->d->ownIdentifier); } XML_Char * SpiffProps::stealLicense() { return SpiffData::stealHelper(this->d->license, this->d->ownLicense); } pair * SpiffProps::stealFirstAttribution() { return stealFirstHelper(this->d->attributions); } SpiffDateTime * SpiffProps::stealDate() { return stealHelper(this->d->date, this->d->ownDate); } void SpiffProps::setVersion(int version) { this->d->version = version; } const XML_Char * SpiffProps::getLicense() const { return this->d->license; } const XML_Char * SpiffProps::getLocation() const { return this->d->location; } const XML_Char * SpiffProps::getIdentifier() const { return this->d->identifier; } pair * SpiffProps::getAttribution(int index) const { return getHelper(this->d->attributions, index); } const SpiffDateTime * SpiffProps::getDate() const { return this->d->date; } int SpiffProps::getVersion() const { return this->d->version; } int SpiffProps::getAttributionCount() const { return (this->d->attributions == NULL) ? 0 : static_cast(this->d->attributions->size()); } /*static*/ void SpiffProps::appendHelper( std::deque *> *> * & container, const XML_Char * value, bool ownership, bool isLocation) { if (container == NULL) { container = new deque *> *>; } pair * const second = new pair(value, ownership); pair *> * const entry = new pair *>(isLocation, second); container->push_back(entry); } /*static*/ pair * SpiffProps::getHelper( std::deque *> *> * & container, int index) { if ((container == NULL) || container->empty() || (index < 0) || (index >= static_cast(container->size()))) { return NULL; } pair *> * const entry = container->at(index); // NOTE: getX() just peeps at data so don't clone anything pair * const res = new pair( entry->first, entry->second->first); return res; } /*static*/ SpiffDateTime * SpiffProps::stealHelper( const SpiffDateTime * & dateTime, bool own) { const SpiffDateTime * const res = Toolbox::getSetNull(dateTime); if (own) { return const_cast(res); } else if (res == NULL) { return NULL; } else { return res->clone(); } } /*static*/ pair * SpiffProps::stealFirstHelper( std::deque *> *> * & container) { if ((container == NULL) || container->empty()) { return NULL; } pair *> * const entry = container->front(); container->pop_front(); pair * const res = new pair( entry->first, entry->second->second ? const_cast(entry->second->first) : Toolbox::newAndCopy(entry->second->first)); delete entry->second; delete entry; return res; } /*static*/ void SpiffProps::deleteNewAndCopy(const SpiffDateTime * & dest, bool & destOwnership, const SpiffDateTime * source, bool sourceCopy) { // Delete old memory if owner if (destOwnership && (dest != NULL)) { delete [] dest; } if (source == NULL) { dest = NULL; destOwnership = false; } else { // Copy new memory if desired if (sourceCopy) { SpiffDateTime * const dup = source->clone(); dest = dup; destOwnership = true; } else { dest = source; destOwnership = false; } } } }