/* * spiff_c - Simple C interface for libSpiff * * Copyright (C) 2007, Ed Schouten / 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. * * Ed Schouten */ /** * @file spiff_c.cpp * @brief Simple libSpiff C bindings. */ #include #include #include #include #include #include #include #include extern "C" { #include "spiff_c.h" } using namespace Spiff; /** * @brief Spiff list reading callback, which stores data in a specific * C-style Spiff list. */ class SpiffCReaderCallback : public SpiffReaderCallback { private: /** * @brief The C-style Spiff list the tracks should be appended * to. */ spiff_list *list; /** * @brief Pointer to the `next' field in the last inserted item * for improving append speed. */ spiff_track **newtrack; /** * @brief Callback which adds tracks to the spiff_list. */ void addTrack(SpiffTrack *track); /** * @brief Callback which sets properties in the spiff_list. */ void setProps(SpiffProps *props); public: /** * @brief Create callback interface for filling a spiff_list. */ SpiffCReaderCallback(spiff_list *list); /** * @brief Finalize the spiff_list. */ virtual ~SpiffCReaderCallback(); }; SpiffCReaderCallback::SpiffCReaderCallback(spiff_list *list) { this->list = list; newtrack = &list->tracks; } SpiffCReaderCallback::~SpiffCReaderCallback() { /* Null-terminate the tracks list */ *newtrack = NULL; } void SpiffCReaderCallback::addTrack(SpiffTrack *track) { spiff_mvalue **newmv; char *str; /* Append new item to the track list */ *newtrack = new spiff_track; (*newtrack)->title = track->stealTitle(); (*newtrack)->album = track->stealAlbum(); (*newtrack)->duration = track->getDuration(); (*newtrack)->tracknum = track->getTrackNum(); /* Locations */ newmv = &(*newtrack)->locations; while ((str = track->stealFirstLocation()) != NULL) { *newmv = new spiff_mvalue; (*newmv)->value = str; /* On to the next location */ newmv = &(*newmv)->next; } *newmv = NULL; /* Identifiers */ newmv = &(*newtrack)->identifiers; while ((str = track->stealFirstIdentifier()) != NULL) { *newmv = new spiff_mvalue; (*newmv)->value = str; /* On to the next location */ newmv = &(*newmv)->next; } *newmv = NULL; /* Clean up and move to the next track */ delete track; newtrack = &(*newtrack)->next; } void SpiffCReaderCallback::setProps(SpiffProps *props) { list->license = props->stealLicense(); list->location = props->stealLocation(); list->identifier = props->stealIdentifier(); delete props; } /** * @brief Deallocate all objects in a spiff_mvalue linked list. */ static void spiff_mvalue_free(struct spiff_mvalue *mv) { struct spiff_mvalue *nmv; for (; mv != NULL; mv = nmv) { /* Back-up pointer */ nmv = mv->next; delete [] mv->value; delete mv; } } /* * Public C interface */ extern "C" struct spiff_list * spiff_parse(const char *filename) { SpiffReader read; spiff_list *ret; /* Allocate empty playlist */ ret = new spiff_list; /* Fill the list with parser results */ SpiffCReaderCallback readcb(ret); if (read.parseFile(filename, &readcb) == SPIFF_READER_SUCCESS) { /* Success */ return (ret); } else { /* Malformed/non-existent list */ delete ret; return (NULL); } } extern "C" struct spiff_list * spiff_new(void) { spiff_list *ret; ret = new spiff_list; ret->license = NULL; ret->location = NULL; ret->identifier = NULL; ret->tracks = NULL; return (ret); } extern "C" void spiff_free(struct spiff_list *list) { spiff_track *tr, *ntr; delete [] list->license; delete [] list->location; delete [] list->identifier; for (tr = list->tracks; tr != NULL; tr = ntr) { /* Back-up pointer */ ntr = tr->next; delete [] tr->title; delete [] tr->album; spiff_mvalue_free(tr->locations); spiff_mvalue_free(tr->identifiers); delete tr; } delete list; } extern "C" void spiff_setvalue(char **str, const char *nstr) { /* Delete old string */ delete [] *str; if (nstr == NULL) { /* Unset value */ *str = NULL; } else { /* Copy value */ size_t len; len = strlen(nstr) + 1; *str = new char[len]; strcpy(*str, nstr); } } extern "C" struct spiff_mvalue * spiff_new_mvalue_before(struct spiff_mvalue **mvalue) { spiff_mvalue *ret; ret = new spiff_mvalue; ret->value = NULL; ret->next = *mvalue; *mvalue = ret; return (ret); } extern "C" struct spiff_track * spiff_new_track_before(struct spiff_track **track) { spiff_track *ret; ret = new spiff_track; ret->title = NULL; ret->album = NULL; ret->duration = -1; ret->tracknum = -1; ret->locations = NULL; ret->identifiers = NULL; ret->next = *track; *track = ret; return (ret); } int spiff_write(struct spiff_list *list, const char *filename) { spiff_track *strack; spiff_mvalue *smvalue; SpiffIndentFormatter formatter(-2); SpiffProps props; /* Playlist properties */ props.lendLicense(list->license); props.lendLocation(list->location); props.lendIdentifier(list->identifier); SpiffPropsWriter pwriter(&props); SpiffTrackWriter twriter; SpiffWriter writer(1, formatter, pwriter); SPIFF_LIST_FOREACH_TRACK(list, strack) { /* Tracks */ SpiffTrack track; track.lendTitle(strack->title); track.lendAlbum(strack->album); track.setDuration(strack->duration); track.setTrackNum(strack->tracknum); /* Track locations and identifiers */ SPIFF_TRACK_FOREACH_LOCATION(strack,smvalue) track.lendAppendLocation(smvalue->value); SPIFF_TRACK_FOREACH_IDENTIFIER(strack, smvalue) track.lendAppendIdentifier(smvalue->value); twriter.setTrack(&track); writer.addTrack(twriter); } return (writer.writeFile(filename)); }