/**
 * @mainpage
 *
 * @section SEC_INTRO Introduction
 * Welcome to the short libSpiff integration tutorial.
 * I recommend using this tutorial together with the
 * code samples in the <c>examples</c> folder; one
 * of these two sources is likely to answer your questions.
 * Drop me a line if you need further help and I will see what
 * I can do for you. So on with the tutorial.
 *
 * @section SEC_READING Reading a playlist
 * To read an XSPF playlist you first need a reader instance:
 * 
 * @code
 * 	SpiffReader reader;
 * @endcode
 * 
 * You use the reader like this:
 * 
 * @code
 * 	reader.parseFile(_PT("playlist.xspf"), NULL);
 * @endcode
 * 
 * That _PT() thing is a macro to support Unicode.
 * More details on this later.
 * The second parameter is the callback object that
 * will receive playlist and track information as
 * they are made available; it can be <c>NULL</c> if you just
 * want to verify that the given file is valid XSPF
 * version 0 or 1 but do not need any more specific
 * information about it. In general it is a pointer
 * to an instance of a class derived from SpiffReaderCallback.
 * That means it has to implement two functions:
 * 
 * @code
 * 	void addTrack(SpiffTrack * track);
 * 	void setProps(SpiffProps * props);
 * @endcode
 * 
 * These functions are called by the reader when new
 * information is made available; setProps() will
 * be called once per playlist (if the reader has not
 * stopped before due to an error) but addTrack() can
 * be called multiple times.
 * 
 * @remarks
 * The callback model was copied from Expat,
 * the underlying XML parser; this model does not
 * need the whole XML tree in memory at a time,
 * thus it is more memory-friendly.
 * 
 * These two functions have to do very similar
 * work: They are passed a data object which they
 * can analyze (by calling methods starting with "get")
 * or <i>steal</i> properties from (by calling methods starting with "steal").
 *
 * @attention
 * Both of these functions have to delete the track/props when
 * they are done to prevent memory leakage or decide to keep them
 * for later; the reader will not do this work for you!
 * Furthermore when deleting the track/props instance all
 * memory not previously <i>stolen</i> from it will also be deleted
 * by the destructor.
 * <i>Stealing</i> means transferring the memory's ownership and preventing
 * it from getting deleted. To avoid memory leakage you should delete
 * the stolen memory yourself later.
 * 
 * @remarks
 * The whole steal-analyze-model was introduced to reduce
 * the number of unnecessary copy operations and therefore
 * speed up the parsing process.
 * 
 * When reading is finished the value returned from parseFile() will be
 * either <c>SPIFF_READER_SUCCESS</c> or one of the error codes.
 * In the latter case you can call getErrorLine() to find out
 * in what line the error occurred and getErrorText() to get a short
 * error information.
 *
 * @attention
 * Please note that the pointer returned from
 * getErrorText() is only valid as long as the reader instance lives.
 * Also note that even if parseFile() returns with an error addTrack()
 * or setProps() might have been called already.
 *
 *
 * 
 * @section SEC_WRITING Writing a playlist
 * To write an XSPF playlist file you first need a writer instance:
 *
 * @code
 * 	SpiffWriter writer(1, layout, propsWriter);
 * @endcode
 * 
 * The first parameter is the XSPF version number which currently
 * can be 0 or 1. The second parameter is an callback XML formatter
 * (an instance of a class derived from SpiffXmlFormatter)
 * which will mainly control the whitespace in the XML output.
 * libSpiff already comes with two built-in formatters:
 * SpiffIndentFormatter which creates well-indented XML output
 * and SpiffSeamlessFormatter which does not create any whitespace at all.
 * The third parameter - "propsWriter" here - is a writer whose
 * job is to take care of the playlist property part. You can think
 * of it as the counterpart to setProperties of the reader callback.
 * A basic playlist property writer can be created like this:
 * 
 * @code
 * 	SpiffProps props;
 * 	SpiffPropsWriter propsWriter(&props);
 * @endcode
 * 
 * As you can see it wraps a SpiffProps instance. That instance can
 * be modified before or after the wrapping to hold the information
 * you want the output playlist to have. For example you set the
 * playlist's creation time like this:
 * 
 * @code
 * 	SpiffDateTime dateTime(2006, 8, 28, 11, 30, 11, 1, 0);
 * 	props.lendDate(&dateTime);
 * @endcode
 * 
 * Similar to the steal/get duality introduced earlier you have to choose
 * between the "lend" and "give" function family when setting
 * information. The whole thing again is only about memory ownership:
 * The lend functions do not transfer ownership, the give functions do.
 * The give family also offers to copy the memory or to assign
 * existing memory. To make this more clear calling 
 *
 * @code
 * 	props.giveTitle(_PT("Some title"), false); // false == do not copy
 * @endcode
 * 
 * would be a bad idea since the memory would not be copied but
 * deleted on destruction. You should use
 *
 * @code
 * 	props.lendTitle(_PT("Some title"));
 * @endcode
 * 
 * in this case.
 *
 * Back to the writer: When you have created a SpiffWriter instance
 * you can let it write its content to file:
 *
 * @code
 * 	writer.writeFile(_PT("TEST.xspf"));
 * @endcode
 * 
 * In this case that would make a valid playlist without any tracks.
 * So before writing the playlist you should add your tracks:
 *
 * @code
 * 	SpiffTrack track;
 * 	SpiffTrackWriter trackWriter;
 * 	trackWriter.setTrack(&track);
 * 	track.lendCreator(_PT("Breaking Benjamin"));
 * 	writer.addTrack(trackWriter);
 * @endcode
 * 
 * When addTrack() is called the track information is appended to an
 * internal buffer which is written when writeFile() is called eventually.
 * You can add the same track several times, you can reuse the track writer,
 * you can call writeFile() several times to write the same playlist to several
 * files; what you cannot do is add more tracks after writing the playlist
 * to a file: You have to call reset() to start over with an empty track list.
 * 
 * 
 * Good luck with your application! libSpiff integration questions are always welcome.
 *
 */
