<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> | |
<HTML> | |
<HEAD> | |
<TITLE>ID3v2.3 Programming Guidelines</TITLE> | |
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> | |
<META NAME="GENERATOR" CONTENT="Mozilla/3.04Gold (WinNT; I) [Netscape]"> | |
<link href="id3lib.css" rel="stylesheet" type="text/css"> | |
</HEAD> | |
<BODY> | |
<h1>ID3v2.3 Programming Guidelines</h1> | |
<center><IMG SRC="id3v2.gif" HEIGHT=50 WIDTH=52></centeR> | |
<P>Applies to: ID3v2.3<BR> | |
Old versions: <A HREF="id3g-2.htm">ID3v2.2 Guidelines</A> (ID3v2.2 is obsolete | |
and should not be used for new tags.)</P> | |
<H2>Table of Contents</H2> | |
<P>1. <A HREF="#Intro">Introduction</A> <BR> | |
1.1. <A HREF="#Usage">Use of this document</A> <BR> | |
2. <A HREF="#id3v23new">What's new</A> in ID3v2.3? <BR> | |
3. Programming Considerations <BR> | |
3.1 <A HREF="#padding">Padding</A> <BR> | |
3.2 <A HREF="#ROmedia">Read-only media</A> <BR> | |
3.3 <A HREF="#SmallFrames">"Insignificant" | |
frames</A> <BR> | |
3.4 <A HREF="#iformat">Preferred image formats</A> | |
<BR> | |
3.5 <A HREF="#manytags">Multiple tags</A> <BR> | |
3.6 <A HREF="#unsync">Unsynchronization</A> <BR> | |
4. Pitfalls & General Advice <BR> | |
4.1 <A HREF="#rtfm">RTFM</A> and yes, the details | |
matter! <BR> | |
4.2 <A HREF="#cB4e">Compression before encryption</A> | |
<BR> | |
4.3 <A HREF="#userErr">Validating user input</A> | |
<BR> | |
5. <A HREF="#Credit">Credits</A> <BR> | |
6. <A HREF="#Refs">References</A> <BR> | |
7. <A HREF="#copyright">Copyright & Legal Notices</A> </P> | |
<P> | |
<HR></P> | |
<H2><A NAME="Intro"></A>Introduction</H2> | |
<P>There are many people who enjoy .MP3 compressed music. The MP3 specification | |
only defined the storage of musical data and did not provide the storage | |
of metadata related to the musical composition; e.g., title, composer and | |
artist, publisher, etc. The ID3 tag standard was created to remedy this | |
need... </P> | |
<P><B>Rationale:</B> Specifications are like grammar: they provide the | |
rules of formatting data but few clues as to how to speak concisely and | |
efficiently. The goal of this document is to answer the "Should I | |
do..." and "Would doing X make it easier/faster/smaller..." | |
type questions. </P> | |
<P><B>Audience:</B> This document is geared toward programmers dealing | |
directly with ID3v2.3 tags. There is a heavy slant towards writing tags | |
correctly since decoding is relatively straightforward. You should familiarize | |
yourself with the <A HREF="http://www.id3.org/develop.html">ID3v2 and related | |
standards</A> since this document refers to and uses the terminology from | |
those documents.</P> | |
<P><B>Coverage:</B> Although ID3v2 tags were created for use with | |
MPEG Layer-3 audio streams, flexibility was a goal from the start. | |
Even though much of this document refers to .MP3 files, the principles | |
are generally applicable to other formats.</P> | |
<P> | |
<HR WIDTH="85%"></P> | |
<H2><A NAME="Usage"></A>Use of this document</H2> | |
<P>These are merely Guidelines and as such they are not part of the ID3v2 | |
standard. </P> | |
<OL> | |
<LI>If anything in this document contradicts the published ID3v2 standard, | |
then the standard shall prevail. The ID3v2 standard always has the final | |
word. | |
<LI>These Guidelines are not binding on anyone (whereas the standard <I>is</I> | |
binding, for obvious reasons.) This means you, as a programmer, should | |
never assume anyone else will abide by these guidelines. A protocol designer | |
once said: | |
<OL> | |
<P><I>"Be flexible in what you accept, but strict in what you write."</I> | |
</P> | |
</OL> | |
<LI>Use your judgement and common sense.</LI> | |
</OL> | |
<P> | |
<HR WIDTH="85%"></P> | |
<H2><A NAME="id3v23new"></A>What's new in ID3v2.3?</H2> | |
<P>For starters, the naming convention changed. "ID3v2" now refers | |
to the family of frame-based tagging methods which utilize the 10-byte | |
header beginning with "ID3" followed by version information. | |
"ID3v2<B>.3.0</B>" refers to the informal standard dated September | |
1998. The informal standard formerly known as "ID3v2" has been | |
renamed to "ID3v2.2"</P> | |
<P>This document concentrates on ID3v2.3. The previous standard, ID3v2.2, is now | |
obsolete; the Guidelines for ID3v2.2 may still be found <A HREF="id3g-2.htm">here</A>.</P> | |
<P>A summary of the differences between ID3v2.3.0 and v2.2 is listed below. | |
Section numbers match the | |
<A HREF="http://www.lysator.liu.se/id3v2/id3v2.3.0.txt">ID3v2.3.0 Informal Standard</A>.</P> | |
<H3>Structural changes:</H3> | |
<UL> | |
<LI>The <B>Frame Header</B> has been expanded. The Frame ID and Frame Size | |
fields are now four bytes long. Two bytes of Flags have been added. See | |
§3.3.</LI> | |
<LI>An optional <B>Extended Header</B> can follow the ID3v2 tag header | |
§3.2. Among other things, the extended header can store a CRC of the | |
entire tag.</LI> | |
</UL> | |
<H3>Clarifications:</H3> | |
<UL> | |
<LI>Pre-defined Frame IDs have been renamed to four characters long.</LI> | |
<LI>Unicode strings are now <I>required</I> to start with the Byte Order Mark (BOM) | |
character. See §3.3.</LI> | |
<LI>Compression and encryption are done on a frame-by-frame basis. The | |
compression algorithm are those offered in zlib. §3.3</LI> | |
<LI>Attached Picture [APIC] frame: the Image Format field has been | |
replaced MIME Type §4.15.</LI> | |
</UL> | |
<P><B>New frames:</B> </P> | |
<UL> | |
<LI>Position Synchronization frame [POSS] §4.22</LI> | |
<LI>Terms of Use frame [USER] §4.23</LI> | |
<LI>Ownership frame [OWNE] §4.24</LI> | |
<LI>Commercial frame [COMR] §4.25</LI> | |
<LI>Private frame [PRIV] §4.28</LI> | |
<LI>Encryption Method Registration [ENCR] §4.25</LI> | |
<LI>Group ID Registration [GRID] §4.26.Used in conjunction with | |
new frame features described in §3.3</LI> | |
<LI>Text frames: Internet Radio Station Name [TRSN] and Internet Radio | |
Station Owner [TRSO]</LI> | |
<LI>URL link frames: Official internet radio station homepage | |
[WORS] and Payment [WPAY]</LI> | |
</UL> | |
<P><B>Deleted frames:</B> Encrypted meta-frame.</P> | |
<P> | |
<HR WIDTH="85%"></P> | |
<H2><A NAME="padding"></A>3.1 Padding</H2> | |
<P>The use of padding and how much should be used has been a matter of | |
debate ever since the first draft of ID3v2. (Take a look in the mailing | |
list <A HREF="http://www.id3.org/maillist.html">archives</A> for arguments.)</P> | |
<P>Before making recommendations let's quantify the issue:</P> | |
<UL> | |
<LI>A two minute song compressed at 44Khz and 128Kb/sec takes about 1990K (slightly | |
less than 2MB) of disk space. The average size of .MP3 files in my | |
collection is 3.5MB</LI> | |
<LI>ID3v1 and Lyrics3 tags are only 128 bytes and 3K, respectively - and | |
they served most songs just fine.</LI> | |
<LI>An ID3v2 tag with basic information (title, artist/composer, copyright) is | |
typically less than 1K in size. Toss in publisher information and lyrics | |
and it comes out to 3K or so.</LI> | |
<LI>Adding a 3K tag to a 2MB song will increase its size by 0.15%</LI> | |
<LI>Adding a 10K tag to a 2MB song increases its size by 0.5%</LI> | |
<LI>Suppose a CD-ROM holds 160 songs. Tagging all of them with 3K | |
tags requires less than a megabyte.</LI> | |
</UL> | |
<P>So in reality tags are tiny compared to the amount of audio data accompanying | |
it. A few KB of padding will not increase the file size noticeably. Remember | |
also the padding is required to be 0's, which means on a slow modem link | |
the padding is compressed significantly.</P> | |
<P>There is but one reason to use padding: since ID3v2 tags are stored | |
at the beginning of the file, it would be a major pain to rewrite the entire | |
multi-megabyte file to add a 50-byte frame. Padding reserves space in advance.</P> | |
<P>The issue then is how much padding should be used. </P> | |
<P><B>James's</B> recommendations:</P> | |
<UL> | |
<LI>What do most people care about? Probably title, artist, composer, | |
band, publisher, lyrics and copyright. 4K will usually be enough for all | |
that plus some miscellaneous information such as media type, file size, | |
playcounter, time codes, etc.</LI> | |
<LI>If you are editing an existing tag and run out of room (meaning you | |
must rewrite the entire file) then double the amount of space reserved | |
for the tag. For example, a file has a 4K tag filled with 3K of data. User | |
wants to add 2K of data, so you rewrite the file reserving 8K at the beginning; | |
then save the 5K of data and leaving 3K of padding. </LI> | |
<P>Obviously there should be an upper bound on doubling; a reasonable number | |
would be 16K or 32K. For example, a file has a 25K tag but only 4K of padding | |
left and the user wants to add 7K of new data. Rewrite the file and reserve | |
41K: save 28K of tag data and leave 13K of padding.</P> | |
<LI>Pictures are large and vary in size. If there are pictures then you | |
should add more padding; use your judgement here.</LI> | |
<LI>Do not forgo padding in files destined for read-only media or streaming | |
applications. The user may want to save the file to another location and | |
edit the tag.</LI> | |
<LI>Include an option to let the user disable padding if (s)he <I>really</I> | |
wants to.</LI> | |
</UL> | |
<P><B>Martin</B> has a good idea: Add enough padding to round out the file | |
to a full cluster. Obviously a minimum amount of padding has to be added | |
to be useful, but beyond the minimum, everything up to the next cluster | |
size will not occupy additional disk space. (Each operating system has | |
its own terminology; Microsoft uses <I>cluster,</I> Apple uses <I>allocation | |
block</I>. How files are stored on disk is beyond the scope of this document; | |
consult an OS book and API reference for details.)</P> | |
<P>Here are some common cluster sizes:</P> | |
<TABLE BORDER=1 > | |
<TR> | |
<TH ROWSPAN="2" NOWRAP>Operating system<BR> | |
(file system type)</TH> | |
<TH ALIGN=CENTER COLSPAN="7" NOWRAP>Disk size </TH> | |
</TR> | |
<TR> | |
<TD>< 256MB</TD> | |
<TD>up to 512MB</TD> | |
<TD>up to 1GB</TD> | |
<TD>up to 2GB</TD> | |
<TD>up to 8GB</TD> | |
<TD>up to 16GB</TD> | |
<TD>> 16GB</TD> | |
</TR> | |
<TR> | |
<TD>DOS & Windows 95<BR> | |
(FAT16)</TD> | |
<TD ALIGN=CENTER>4K</TD> | |
<TD ALIGN=CENTER>8K</TD> | |
<TD ALIGN=CENTER>16K</TD> | |
<TD ALIGN=CENTER>32K</TD> | |
<TD ALIGN=CENTER COLSPAN="3">N/A<BR> | |
(FAT16 can't handle drives > 4GB)</TD> | |
</TR> | |
<TR> | |
<TD>Win95 OSR2 & Win98<BR> | |
(FAT32)</TD> | |
<TD ALIGN=CENTER>N/A</TD> | |
<TD ALIGN=CENTER COLSPAN="4">4K</TD> | |
<TD ALIGN=CENTER>8K</TD> | |
<TD ALIGN=CENTER>16K or 32K</TD> | |
</TR> | |
<TR> | |
<TD>Windows NT<BR> | |
(NTFS)</TD> | |
<TD ALIGN=CENTER COLSPAN="7">0.5K to 64K<BR> | |
(0.5K to 4K clusters are most common)</TD> | |
</TR> | |
<TR> | |
<TD>MacOS pre-8.1<BR> | |
(HFS)</TD> | |
<TD ALIGN=CENTER>0.5K - 4K</TD> | |
<TD ALIGN=CENTER>4.5K - 8K</TD> | |
<TD ALIGN=CENTER>8.5K - 16K</TD> | |
<TD ALIGN=CENTER>16.5K - 32K</TD> | |
<TD ALIGN=CENTER COLSPAN="3">N/A<BR> | |
(HFS can't handle disks > 2GB)</TD> | |
</TR> | |
<TR> | |
<TD>MacOS 8.1 and later<BR> | |
(HFS+)</TD> | |
<TD ALIGN=CENTER>0.5K</TD> | |
<TD ALIGN=CENTER>1K</TD> | |
<TD ALIGN=CENTER>2K</TD> | |
<TD ALIGN=CENTER COLSPAN="4">Default is 4K; user-selectable up to 4K</TD> | |
</TR> | |
<TR> | |
<TD>CD-ROM, 650MB<BR> | |
(ISO 9660)</TD> | |
<TD ALIGN=CENTER COLSPAN="3">always 2K</TD> | |
</TR> | |
<TR> | |
<TD>DVD-ROM<BR> | |
(UDF)</TD> | |
<TD ALIGN=CENTER COLSPAN="7">always 2K</TD> | |
</TR> | |
</TABLE> | |
<P>Advanced operating systems employ tricks to optimize disk space. For | |
example, Novell NetWare 4 uses 64K disk blocks but can split a block into | |
0.5K pieces, thus creating the illusion of 512-byte blocks. UNIX file | |
systems have their own methods to utilize disk space efficiently.</P> | |
<P><B>James's</B> shortcut on choosing an appropriate cluster size: 2K | |
(Nice even number, not too big, not too small)</P> | |
<H2><A NAME="ROmedia"></A>3.2 Read-only media</H2> | |
<P>Never assume a .MP3 file is writable unless the user is specifically | |
editing the tag. MP3 files can be stored on read-only media such as a CD-ROM | |
or a network share. If the user is editing the tag, it is an error if the | |
file is write-protected because the user's changes cannot be saved. If | |
a player is merely updating the playcounter or popularity-meter, it should | |
not pop up a message complaining the file cannot be written to. </P> | |
<P><B>James</B>: Include a visual cue to indicate whether the file is write-protected. | |
For example, a small icon similar in size and color to the stereo indicator | |
in WinAMP. A quick glance will determine whether certain settings will | |
be saved. </P> | |
<H2><A NAME="SmallFrames"></A>3.3 "Insignificant" frames</H2> | |
<P>"Insignificant" frames are small frames that don't necessarily | |
have meaning when a ID3v2 tag is created. The issue is whether the tag | |
editor should add these frames when they do not already exist. </P> | |
<P>For example, if Joe is adding tags to a fresh batch of .MP3 files, should | |
the tag editor include a playcounter [PCNT] frame in the tag? The tag editor | |
has no idea how many times the particular file has been played; unless | |
Joe tells it otherwise, the editor has to create a [PCNT] frame with a | |
count of 0. </P> | |
<P>There are two ways to look at this. On the one hand, the frame is so | |
small it takes almost no effort to include it. Since there will usually | |
be a few hundred bytes of padding, the ten bytes used by the counter frame | |
is in a sense "free." A player will probably add it later anyway | |
when the file is used. </P> | |
<P>On the other hand, if the frame is not holding useful information, why | |
bother adding it? Padding, if used, effectively reserves space for these | |
frames. Consider also the absence of a frame can be meaningful: the lack | |
of a playcounter frame may indicate "I do not know how many times | |
this piece has been played" as opposed to a count of 0, which | |
indicates "This song has never been played." </P> | |
<P>These can be considered "insignificant" frames: </P> | |
<UL> | |
<LI>Playcounter [PCNT]<BR> | |
(<B>James</B>: an integrated ripper-encoder-tagger can include a playcount | |
of 0 in newly created files, since by definition they have never been used..) | |
</LI> | |
<LI>Others, anyone?</LI> | |
</UL> | |
<P><B>Martin</B>: It is considered good manner to allow the user to disable | |
writing of frames (s)he doesn't want. At least in an advanced menu in a | |
hidden place. Perhaps the user doesn't want the TSI, TLE, TMT and MLL frame | |
to be added automatically, even though it might be the default setting.</P> | |
<H2><A NAME="iformat"></A>3.4 Preferred image formats</H2> | |
<P>A question Martin gets often is why the ID3v2 document says "... | |
PNG and JPEG picture format should be used..." Interoperability | |
means it is almost guaranteed another ID3v2 tag/picture decoder can handle | |
the PNG and JPEG formats. The chances a Macintosh application can display | |
BMP files are slim; likewise, the complexities of EPS and TIFF are best | |
left out.</P> | |
<P>Consider these other arguments favoring PNG and JPEG:</P> | |
<UL> | |
<LI>PNG compresses better than BMP, GIF and most other lossless formats.</LI> | |
<LI>JPEG has superior compression to most formats, especially for photographic | |
pictures. (JPEG is not suitable for line-art and computer-generated graphics | |
- use PNG for these.)</LI> | |
<LI>Both formats are patent- and royalty-free (which is not the case with | |
GIF, whose LZW compression algorithm is patented by Unisys.) </LI> | |
</UL> | |
<P><B>Martin</B>: The freedom to use whatever format you like in the picture | |
frame is of course a freedom under responsibility. Do you want to make | |
cross platform tags? Do you want to avoid legal trouble, at least for the | |
principle? If so, use PNG and JPEG.</P> | |
<P><B>Dirk</B>: Applications may want to convert the incoming picture type | |
to PNG or JPEG first, or failing that, at least inform the user that they | |
<I>should</I> be using PNG or JPEG, but allow the user to override this | |
if they insist on using, say, a PCX.</P> | |
<H2><A NAME="manytags"></A>3.5 Multiple tags</H2> | |
<P>Decoders should be prepared to handle multiple ID3v2 tags per stream. | |
This is especially important for players/decoders wanting to handle netradio-type | |
applications since the notion of distinct files may not apply. </P> | |
<P><B>Dirk</B>: An easy way to achieve this would be to use a central 'frame | |
dispatch' routine, kind of like a demultiplexer. </P> | |
<H2><A NAME="unsync"></A>3.6 Unsynchronization</H2> | |
<P>The ID3v2 standard states "The only purpose of the 'unsychronisation | |
scheme' is to make the ID3v2 tag as compatible as possible with existing | |
software <I>[at the time the ID3v2.2 standard was drafted]</I>" What | |
are the implications?</P> | |
<OL> | |
<LI>.MP3 decoders, regardless of age, will not be affected by extraneous | |
data (i.e., tags) that does not contain a MPEG sync sequence.</LI> | |
<LI>There is minimal impact if a decoder does not recognize ID3v2 tags | |
but encounters something with a sync sequence. At worst a click or pop | |
will be heard at the beginning of the piece, as if some data corruption | |
has occurred.</LI> | |
<LI>New software is expected to take advantage of ID3v2. Unsynchronization | |
is not necessary with ID3v2 compliant software.</LI> | |
</OL> | |
<P>(Software which does not behave according to items 1 and 2 above are | |
categorically deemed "broken." Microsoft's Media Player is an | |
example of such software.)</P> | |
<P><B>Martin</B>: I believe that unsynchronization should be done as seldom | |
as possible since it increases the size of the tag as well as the parsing | |
time. In other words, I think unsynchronization should be turned off as | |
default.</P> | |
<P>However, it is important to be able to undo unsynchronization when reading | |
tags; otherwise unsynchronized tags will not be read correctly.</P> | |
<P> | |
<HR WIDTH="85%"></P> | |
<H2><A NAME="rtfm"></A>4.1 RTFM (details are important!)</H2> | |
<P>When the ID3v2 document refers to another standard it is assumed that | |
the implementor is familiar with that standard as well. When it says URL | |
it does not mean 'www.buymusic.com', it means 'http://www.buymusic.com/' | |
A "URL containing an e-mail address" must include the | |
'mailto:' qualifier. Those who at least take a quick look at the related | |
standards will not make these kinds of mistakes.</P> | |
<P>If these details are so important, why aren't they spelled out in the | |
ID3v2 standard? According to Martin, "There has been people who said | |
to me, 'You must write these kind of things in the document, or else people | |
will make these mistakes.' The latest ID3 v2.01 draft is <I>only</I> 74,657 | |
bytes of pure text because I did not. Guess why there are references to | |
the standards in the document!" </P> | |
<H2><A NAME="cB4e"></A>4.2 Compression before encryption</H2> | |
<P>Encryption works by scrambling data to produce what amounts to random | |
bits for an attacker. Data compression works by replacing or removing redundant | |
information. It follows that the output of any decent crypto algorithm | |
will not be compressible; therefore if you wish to use both compression | |
and encryption, you must compress the data before encrypting it. </P> | |
<P>Compressing before encryption also affords better security, since predictable | |
headers and such will be hidden by compression. </P> | |
<P>Remember: <I>compression</I> comes before <I>encryption</I> in the dictionary | |
(at least in English) and that is how it should be in your application. | |
</P> | |
<H2><A NAME="userErr"></A>4.3 Validating user input</H2> | |
<P>Never trust the input from the user to be sensible or formatted correctly. | |
Is the ISRC a valid one? Does the month 13 exist? Could this piece of music | |
be from disc 5 out of a 3 disc set?</P> | |
<P><B>Dirk</B>: Personally, I think having input validation occur | |
when the user signifies that the tag is "finished" is a good | |
way of going about it, if only because I know I'll get half way through | |
something and want to stop and do something else before I forget.</P> | |
<P><B>James</B>: Extremely strict validation becomes restrictions | |
on versatility and usability. An option to turn off or accept potentially | |
invalid data can be included somewhere. For example, by default Microsoft | |
Visual Basic checks for syntax errors as code is entered; however, users | |
can disable that feature if they wish to delay syntax checking until compile | |
time. </P> | |
<P>Things to watch out for (this is by no means an all-inclusive list):</P> | |
<UL> | |
<LI>Properly formatted URLs (see <A HREF="#rtfm">RTFM</A>, above.) But | |
should your application verify whether the URL actually exists? That may | |
be too complicated; Martin and James's opinion is no verification.</LI> | |
<LI>Proper MIME types.</LI> | |
<LI>Are characters valid? Most text fields forbid control characters, | |
even newlines. NULs are not allowed except in Unicode strings or to indicate | |
end-of-string for terminated strings.</LI> | |
<LI>Numerical strings must consist solely of the characters '0' through | |
'9'</LI> | |
<LI>Are lists handled properly? The list separator is a slash: / | |
What happens if the user enters a / in an item?</LI> | |
<LI>Are characters such as ( escaped where necessary?</LI> | |
<LI>Do dates and times make sense? Years must be four digits long and be | |
in the right century. (No Y2K problems here!)</LI> | |
<LI>Is an image really the format the user claims it is? Some people believe | |
renaming a .BMP file to .PNG will change its format accordingly.</LI> | |
</UL> | |
<P>Your application should never crash because the user does something | |
stupid. Likewise, your application should not crash because of erroneous | |
or malformed data in a tag. It is particularly important your application | |
can recognize Unicode text frames and ignore them if the operating system | |
or your program cannot handle Unicode.</P> | |
<P> | |
<HR WIDTH="85%"></P> | |
<H2><A NAME="Credit"></A>Credits & Contributors</H2> | |
<UL> | |
<LI><A HREF="mailto:dirk@id3.org">Dirk Mahoney</A>, creator of the <A HREF="http://www.id3.org/id3lib/">ID3Lib</A> | |
C++ tag processing library.</LI> | |
<LI><A HREF="mailto:merlin@starr.econ.nyu.edu">James Lin</A>, author of | |
these Guidelines.</LI> | |
<LI><A HREF="mailto:nilsson@id3.org">Martin Nilsson</A>, author of the | |
ID3v2 standard.</LI> | |
</UL> | |
<H2><A NAME="Refs"></A>References</H2> | |
<UL> | |
<LI><A HREF="http://www.id3.org/">www.id3.org</A>: Home of the <A HREF="http://www.id3.org/develop.html">ID3v2 | |
Informal Standard</A> and lots of other useful material.</LI> | |
</UL> | |
<P> | |
<HR WIDTH="85%"></P> | |
<H2><A NAME="copyright"></A>Copyright & Legal Notice</H2> | |
<P>Copyright © 1998 James Lin and Merlin's Workshop. </P> | |
<P>The goal of this document is to provide hints on how to implement the | |
ID3v2 standard(s) correctly and efficiently. Distribution of this document | |
is unlimited as long as no changes are made to its content: </P> | |
<P><B>This document and translations of it may be copied and furnished | |
to others, in any format or medium, provided no modifications are made | |
to the content unless written permission has been obtained from the author.</B> | |
</P> | |
<P><B>This document is provided "AS IS" without warranty of any | |
kind, either expressed or implied, including but not limited to, the implied | |
warranties of merchantability and fitness for a particular purpose.</B> | |
</P> | |
<P><B>In no event unless required by applicable law will the author of | |
this document be liable for damages, including any general, special, incidental | |
or consequential damages arising out of the use or inability to use any | |
information (including but not limited to loss or corruption of data or | |
losses sustained by third parties), even if the author has been advised | |
of the possibility of such damages.</B> </P> | |
<HR WIDTH="100%"></hr><p>Copyright © 1998 Merlin's | |
Workshop. <I>Last updated October 22, 1998</I> </P> | |
</BODY> | |
</HTML> |