/* * 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 SpiffTrack.cpp * Implementation of SpiffTrack. */ #include #include #include using namespace Spiff::Toolbox; using namespace std; namespace Spiff { /// @cond DOXYGEN_NON_API /** * D object for SpiffTrack. */ class SpiffTrackPrivate { friend class SpiffTrack; const XML_Char * album; ///< Album bool ownAlbum; ///< Album memory ownership flag std::deque *> * locations; ///< List of URI locations std::deque *> * identifiers; ///< List of URI identifiers int trackNum; ///< Number of the track, must be positive int duration; ///< Duration in milliseconds, must be non-negative /** * Creates a new D object. */ SpiffTrackPrivate() : album(NULL), ownAlbum(false), locations(NULL), identifiers(NULL), trackNum(-1), duration(-1) { } /** * Copy constructor. * * @param source Source to copy from */ SpiffTrackPrivate(const SpiffTrackPrivate & source) : album(source.ownAlbum ? newAndCopy(source.album) : source.album), ownAlbum(source.ownAlbum), locations(NULL), // Created in copyDeque identifiers(NULL), // Created in copyDeque trackNum(source.trackNum), duration(source.duration) { if (source.locations != NULL) { copyDeque(this->locations, source.locations); } if (source.identifiers != NULL) { copyDeque(this->identifiers, source.identifiers); } } /** * Assignment operator. * * @param source Source to copy from */ SpiffTrackPrivate & operator=(const SpiffTrackPrivate & source) { if (this != &source) { // album freeIfOwned(this->album, this->ownAlbum); this->album = source.ownAlbum ? newAndCopy(source.album) : source.album; this->ownAlbum = source.ownAlbum; // locations if (this->locations != NULL) { freeDeque(this->locations); } if (source.locations != NULL) { copyDeque(this->locations, source.locations); } // identifiers if (this->identifiers != NULL) { freeDeque(this->identifiers); } if (source.identifiers != NULL) { copyDeque(this->identifiers, source.identifiers); } this->trackNum = source.trackNum; this->duration = source.duration; } return *this; } /** * Destroys this D object. */ ~SpiffTrackPrivate() { freeIfOwned(this->album, this->ownAlbum); if (this->locations != NULL) { freeDeque(this->locations); } if (this->identifiers != NULL) { freeDeque(this->identifiers); } } static void freeDeque(std::deque< std::pair *> * & container) { 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 void copyDeque(std::deque< std::pair *> * & dest, const std::deque< std::pair *> * source) { deque *>::const_iterator iter = source->begin(); while (iter != source->end()) { pair * const entry = *iter; const bool ownership = entry->second; const XML_Char * const value = ownership ? newAndCopy(entry->first) : entry->first; SpiffTrack::appendHelper(dest, value, ownership); iter++; } } }; /// @endcond SpiffTrack::SpiffTrack() : SpiffData(), d(new SpiffTrackPrivate()) { } SpiffTrack::SpiffTrack(const SpiffTrack & source) : SpiffData(source), d(new SpiffTrackPrivate(*(source.d))) { } SpiffTrack & SpiffTrack::operator=(const SpiffTrack & source) { if (this != &source) { SpiffData::operator=(source); *(this->d) = *(source.d); } return *this; } SpiffTrack::~SpiffTrack() { delete this->d; } void SpiffTrack::giveAlbum(const XML_Char * album, bool copy) { Toolbox::deleteNewAndCopy(this->d->album, this->d->ownAlbum, album, copy); } void SpiffTrack::lendAlbum(const XML_Char * album) { Toolbox::deleteNewAndCopy(this->d->album, this->d->ownAlbum, album, false); } void SpiffTrack::setTrackNum(int trackNum) { this->d->trackNum = trackNum; } void SpiffTrack::setDuration(int duration) { this->d->duration = duration; } int SpiffTrack::getTrackNum() const { return this->d->trackNum; } int SpiffTrack::getDuration() const { return this->d->duration; } XML_Char * SpiffTrack::stealAlbum() { return SpiffData::stealHelper(this->d->album, this->d->ownAlbum); } const XML_Char * SpiffTrack::getAlbum() const { return this->d->album; } void SpiffTrack::giveAppendIdentifier(const XML_Char * identifier, bool copy) { appendHelper(this->d->identifiers, copy ? Toolbox::newAndCopy(identifier) : identifier, true); } void SpiffTrack::giveAppendLocation(const XML_Char * location, bool copy) { appendHelper(this->d->locations, copy ? Toolbox::newAndCopy(location) : location, true); } void SpiffTrack::lendAppendIdentifier(const XML_Char * identifier) { appendHelper(this->d->identifiers, identifier, false); } void SpiffTrack::lendAppendLocation(const XML_Char * location) { appendHelper(this->d->locations, location, false); } XML_Char * SpiffTrack::stealFirstIdentifier() { return stealFirstHelper(this->d->identifiers); } XML_Char * SpiffTrack::stealFirstLocation() { return stealFirstHelper(this->d->locations); } const XML_Char * SpiffTrack::getIdentifier(int index) const { return getHelper(this->d->identifiers, index); } const XML_Char * SpiffTrack::getLocation(int index) const { return getHelper(this->d->locations, index); } int SpiffTrack::getIdentifierCount() const { return (this->d->identifiers == NULL) ? 0 : static_cast(this->d->identifiers->size()); } int SpiffTrack::getLocationCount() const { return (this->d->locations == NULL) ? 0 : static_cast(this->d->locations->size()); } /*static*/ void SpiffTrack::appendHelper( std::deque *> * & container, const XML_Char * value, bool ownership) { if (container == NULL) { container = new deque *>; } pair * const entry = new pair(value, ownership); container->push_back(entry); } /*static*/ XML_Char * SpiffTrack::stealFirstHelper( std::deque *> * & container) { if ((container == NULL) || container->empty()) { return NULL; } pair * const entry = container->front(); container->pop_front(); XML_Char * const res = entry->second ? const_cast(entry->first) : Toolbox::newAndCopy(entry->first); delete entry; return res; } /*static*/ const XML_Char * SpiffTrack::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 return entry->first; } }