/**
* @mainpage
*
* @section SEC_INTRO Introduction
* Welcome to the short libSpiff integration tutorial.
* I recommend using this tutorial together with the
* code samples in the examples 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 NULL 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 steal 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 stolen from it will also be deleted
* by the destructor.
* Stealing 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 SPIFF_READER_SUCCESS 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.
*
*/