/** * @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. * */