/* * 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 SpiffIndentFormatter.cpp * Implementation of SpiffIndentFormatter. */ #include #include namespace Spiff { /** * Specifies the type of basic XML unit. */ enum SpiffElemPos { SPIFF_ELEM_DUMMY, ///< Stack returns 0 if empty SPIFF_ELEM_START, ///< Opening tag SPIFF_ELEM_BODY ///< Tag body }; /// @cond DOXYGEN_NON_API /** * D object for SpiffIndentFormatter. */ class SpiffIndentFormatterPrivate { friend class SpiffIndentFormatter; int level; ///< Element tree depth SpiffStack * stack; ///< Tag position stack bool newlineFinish; ///< Finishing newline flag int shift; ///< Indent shift /** * Creates a new D object. * * @param newlineFinish When true a newline will be appended to the end of the file which is strongly recommended * @param shift Non-positive indent shift (-2 will create two tabs less) */ SpiffIndentFormatterPrivate(bool newlineFinish, int shift) : level(0), stack(new SpiffStack()), newlineFinish(newlineFinish), shift(shift) { } /** * Copy constructor. * * @param source Source to copy from */ SpiffIndentFormatterPrivate(const SpiffIndentFormatterPrivate & source) : level(source.level), stack(new SpiffStack(*(source.stack))), newlineFinish(source.newlineFinish), shift(source.shift) { } /** * Destroys this D object. */ ~SpiffIndentFormatterPrivate() { delete this->stack; } }; /// @endcond SpiffIndentFormatter::SpiffIndentFormatter(bool newlineFinish) : SpiffXmlFormatter(), d(new SpiffIndentFormatterPrivate(newlineFinish, 0)) { } SpiffIndentFormatter::SpiffIndentFormatter(int shift) : SpiffXmlFormatter(), d(new SpiffIndentFormatterPrivate(true, shift)) { // Fix broken indent shift if (this->d->shift > 0) { this->d->shift = 0; } } SpiffIndentFormatter::SpiffIndentFormatter(const SpiffIndentFormatter & source) : SpiffXmlFormatter(source), d(new SpiffIndentFormatterPrivate(*(source.d))) { } SpiffIndentFormatter & SpiffIndentFormatter::operator=(const SpiffIndentFormatter & source) { if (this != &source) { SpiffXmlFormatter::operator=(source); *(this->d) = *(source.d); } return *this; } SpiffIndentFormatter::~SpiffIndentFormatter() { delete this->d; } void SpiffIndentFormatter::writeStart(const XML_Char * name, const XML_Char ** atts) { // XML Header if (!this->introDone) { *this->output << _PT("\n"); this->introDone = true; } else { *this->output << _PT('\n'); } // Indent for (int i = -(this->d->shift); i < this->d->level; i++) { *this->output << _PT('\t'); } // Element *this->output << _PT('<') << name; while (atts[0] != NULL) { *this->output << _PT(' ') << atts[0] << _PT("=\"") << atts[1] << _PT("\""); atts += 2; } *this->output << _PT(">"); this->d->level++; this->d->stack->push(SPIFF_ELEM_START); } void SpiffIndentFormatter::writeEnd(const XML_Char * name) { this->d->level--; if (this->d->stack->top() != SPIFF_ELEM_BODY) { *this->output << _PT('\n'); for (int i = -(this->d->shift); i < this->d->level; i++) { *this->output << _PT('\t'); } } else { // Pop body this->d->stack->pop(); } // Pop start this->d->stack->pop(); *this->output << _PT("'); if ((this->d->level == 0) && this->d->newlineFinish) { *this->output << _PT("\n"); } } void SpiffIndentFormatter::writeBody(const XML_Char * text) { writeCharacterData(text); this->d->stack->push(SPIFF_ELEM_BODY); } void SpiffIndentFormatter::writeBody(int number) { *this->output << number; this->d->stack->push(SPIFF_ELEM_BODY); } }