Added TagLib (with AUTORS and COPYING files) 1.2.0
authorNikolay Tischenko <niktischenko@gmail.com>
Fri, 24 Sep 2010 16:09:14 +0000 (23:09 +0700)
committerNikolay Tischenko <niktischenko@gmail.com>
Fri, 24 Sep 2010 16:09:14 +0000 (23:09 +0700)
Switched to TagLib for tag resolving
Added progressbar to busy widget

166 files changed:
AUTHORS.TagLib [new file with mode: 0644]
COPYING.LGPL [new file with mode: 0644]
resources/someplayer.png
someplayer.pro
src/busywidget.cpp
src/busywidget.h
src/library.cpp
src/library.h
src/mainwindow.cpp
src/mediascanner.cpp
src/someplayer.h
src/taglib/ape/ape-tag-format.txt [new file with mode: 0644]
src/taglib/ape/apefooter.cpp [new file with mode: 0644]
src/taglib/ape/apefooter.h [new file with mode: 0644]
src/taglib/ape/apeitem.cpp [new file with mode: 0644]
src/taglib/ape/apeitem.h [new file with mode: 0644]
src/taglib/ape/apetag.cpp [new file with mode: 0644]
src/taglib/ape/apetag.h [new file with mode: 0644]
src/taglib/asf/asfattribute.cpp [new file with mode: 0644]
src/taglib/asf/asfattribute.h [new file with mode: 0644]
src/taglib/asf/asffile.cpp [new file with mode: 0644]
src/taglib/asf/asffile.h [new file with mode: 0644]
src/taglib/asf/asfproperties.cpp [new file with mode: 0644]
src/taglib/asf/asfproperties.h [new file with mode: 0644]
src/taglib/asf/asftag.cpp [new file with mode: 0644]
src/taglib/asf/asftag.h [new file with mode: 0644]
src/taglib/audioproperties.cpp [new file with mode: 0644]
src/taglib/audioproperties.h [new file with mode: 0644]
src/taglib/fileref.cpp [new file with mode: 0644]
src/taglib/fileref.h [new file with mode: 0644]
src/taglib/flac/flacfile.cpp [new file with mode: 0644]
src/taglib/flac/flacfile.h [new file with mode: 0644]
src/taglib/flac/flacproperties.cpp [new file with mode: 0644]
src/taglib/flac/flacproperties.h [new file with mode: 0644]
src/taglib/mp4/mp4atom.cpp [new file with mode: 0644]
src/taglib/mp4/mp4atom.h [new file with mode: 0644]
src/taglib/mp4/mp4coverart.cpp [new file with mode: 0644]
src/taglib/mp4/mp4coverart.h [new file with mode: 0644]
src/taglib/mp4/mp4file.cpp [new file with mode: 0644]
src/taglib/mp4/mp4file.h [new file with mode: 0644]
src/taglib/mp4/mp4item.cpp [new file with mode: 0644]
src/taglib/mp4/mp4item.h [new file with mode: 0644]
src/taglib/mp4/mp4properties.cpp [new file with mode: 0644]
src/taglib/mp4/mp4properties.h [new file with mode: 0644]
src/taglib/mp4/mp4tag.cpp [new file with mode: 0644]
src/taglib/mp4/mp4tag.h [new file with mode: 0644]
src/taglib/mpc/mpcfile.cpp [new file with mode: 0644]
src/taglib/mpc/mpcfile.h [new file with mode: 0644]
src/taglib/mpc/mpcproperties.cpp [new file with mode: 0644]
src/taglib/mpc/mpcproperties.h [new file with mode: 0644]
src/taglib/mpeg/id3v1/id3v1genres.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v1/id3v1genres.h [new file with mode: 0644]
src/taglib/mpeg/id3v1/id3v1tag.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v1/id3v1tag.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/attachedpictureframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/commentsframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/commentsframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/popularimeterframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/popularimeterframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/privateframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/privateframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/relativevolumeframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/textidentificationframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/textidentificationframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/unknownframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/unknownframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/urllinkframe.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/frames/urllinkframe.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2.2.0.txt [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2.3.0.txt [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2.4.0-frames.txt [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2.4.0-structure.txt [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2extendedheader.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2extendedheader.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2footer.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2footer.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2frame.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2frame.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2framefactory.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2framefactory.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2header.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2header.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2synchdata.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2synchdata.h [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2tag.cpp [new file with mode: 0644]
src/taglib/mpeg/id3v2/id3v2tag.h [new file with mode: 0644]
src/taglib/mpeg/mpegfile.cpp [new file with mode: 0644]
src/taglib/mpeg/mpegfile.h [new file with mode: 0644]
src/taglib/mpeg/mpegheader.cpp [new file with mode: 0644]
src/taglib/mpeg/mpegheader.h [new file with mode: 0644]
src/taglib/mpeg/mpegproperties.cpp [new file with mode: 0644]
src/taglib/mpeg/mpegproperties.h [new file with mode: 0644]
src/taglib/mpeg/xingheader.cpp [new file with mode: 0644]
src/taglib/mpeg/xingheader.h [new file with mode: 0644]
src/taglib/ogg/flac/oggflacfile.cpp [new file with mode: 0644]
src/taglib/ogg/flac/oggflacfile.h [new file with mode: 0644]
src/taglib/ogg/oggfile.cpp [new file with mode: 0644]
src/taglib/ogg/oggfile.h [new file with mode: 0644]
src/taglib/ogg/oggpage.cpp [new file with mode: 0644]
src/taglib/ogg/oggpage.h [new file with mode: 0644]
src/taglib/ogg/oggpageheader.cpp [new file with mode: 0644]
src/taglib/ogg/oggpageheader.h [new file with mode: 0644]
src/taglib/ogg/speex/speexfile.cpp [new file with mode: 0644]
src/taglib/ogg/speex/speexfile.h [new file with mode: 0644]
src/taglib/ogg/speex/speexproperties.cpp [new file with mode: 0644]
src/taglib/ogg/speex/speexproperties.h [new file with mode: 0644]
src/taglib/ogg/vorbis/vorbisfile.cpp [new file with mode: 0644]
src/taglib/ogg/vorbis/vorbisfile.h [new file with mode: 0644]
src/taglib/ogg/vorbis/vorbisproperties.cpp [new file with mode: 0644]
src/taglib/ogg/vorbis/vorbisproperties.h [new file with mode: 0644]
src/taglib/ogg/xiphcomment.cpp [new file with mode: 0644]
src/taglib/ogg/xiphcomment.h [new file with mode: 0644]
src/taglib/riff/aiff/aifffile.cpp [new file with mode: 0644]
src/taglib/riff/aiff/aifffile.h [new file with mode: 0644]
src/taglib/riff/aiff/aiffproperties.cpp [new file with mode: 0644]
src/taglib/riff/aiff/aiffproperties.h [new file with mode: 0644]
src/taglib/riff/rifffile.cpp [new file with mode: 0644]
src/taglib/riff/rifffile.h [new file with mode: 0644]
src/taglib/riff/wav/wavfile.cpp [new file with mode: 0644]
src/taglib/riff/wav/wavfile.h [new file with mode: 0644]
src/taglib/riff/wav/wavproperties.cpp [new file with mode: 0644]
src/taglib/riff/wav/wavproperties.h [new file with mode: 0644]
src/taglib/tag.cpp [new file with mode: 0644]
src/taglib/tag.h [new file with mode: 0644]
src/taglib/taglib_config.h.in [new file with mode: 0644]
src/taglib/taglib_export.h [new file with mode: 0644]
src/taglib/tagunion.cpp [new file with mode: 0644]
src/taglib/tagunion.h [new file with mode: 0644]
src/taglib/toolkit/taglib.h [new file with mode: 0644]
src/taglib/toolkit/tbytevector.cpp [new file with mode: 0644]
src/taglib/toolkit/tbytevector.h [new file with mode: 0644]
src/taglib/toolkit/tbytevectorlist.cpp [new file with mode: 0644]
src/taglib/toolkit/tbytevectorlist.h [new file with mode: 0644]
src/taglib/toolkit/tdebug.cpp [new file with mode: 0644]
src/taglib/toolkit/tdebug.h [new file with mode: 0644]
src/taglib/toolkit/tfile.cpp [new file with mode: 0644]
src/taglib/toolkit/tfile.h [new file with mode: 0644]
src/taglib/toolkit/tlist.h [new file with mode: 0644]
src/taglib/toolkit/tlist.tcc [new file with mode: 0644]
src/taglib/toolkit/tmap.h [new file with mode: 0644]
src/taglib/toolkit/tmap.tcc [new file with mode: 0644]
src/taglib/toolkit/tstring.cpp [new file with mode: 0644]
src/taglib/toolkit/tstring.h [new file with mode: 0644]
src/taglib/toolkit/tstringlist.cpp [new file with mode: 0644]
src/taglib/toolkit/tstringlist.h [new file with mode: 0644]
src/taglib/toolkit/unicode.cpp [new file with mode: 0644]
src/taglib/toolkit/unicode.h [new file with mode: 0644]
src/taglib/trueaudio/trueaudiofile.cpp [new file with mode: 0644]
src/taglib/trueaudio/trueaudiofile.h [new file with mode: 0644]
src/taglib/trueaudio/trueaudioproperties.cpp [new file with mode: 0644]
src/taglib/trueaudio/trueaudioproperties.h [new file with mode: 0644]
src/taglib/wavpack/wavpackfile.cpp [new file with mode: 0644]
src/taglib/wavpack/wavpackfile.h [new file with mode: 0644]
src/taglib/wavpack/wavpackproperties.cpp [new file with mode: 0644]
src/taglib/wavpack/wavpackproperties.h [new file with mode: 0644]
src/tagresolver.cpp
src/tagresolver.h
src/ui/busywidget.ui

diff --git a/AUTHORS.TagLib b/AUTHORS.TagLib
new file mode 100644 (file)
index 0000000..8872bd8
--- /dev/null
@@ -0,0 +1,11 @@
+Scott Wheeler <wheeler@kde.org>
+ Author, maintainer
+Ismael Orenstein <orenstein@kde.org>
+ Xing header implementation
+Allan Sandfeld Jensen <kde@carewolf.org>
+ FLAC metadata implementation
+Teemu Tervo <teemu.tervo@gmx.net>
+ Numerous bug reports and fixes
+
+Please send all patches and questions to taglib-devel@kde.org rather than to
+individual developers!
diff --git a/COPYING.LGPL b/COPYING.LGPL
new file mode 100644 (file)
index 0000000..e38ffa8
--- /dev/null
@@ -0,0 +1,481 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+                    59 Temple Place - Suite 330
+                    Boston, MA 02111-1307, USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+          How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
index ead97fc..31dcd75 100644 (file)
Binary files a/resources/someplayer.png and b/resources/someplayer.png differ
index 0f501be..1269327 100644 (file)
@@ -9,6 +9,25 @@ QT       += core gui phonon sql
 TARGET = someplayer
 TEMPLATE = app
 
+INCLUDEPATH += src/taglib
+INCLUDEPATH += src/taglib/toolkit
+INCLUDEPATH += src/taglib/ape
+INCLUDEPATH += src/taglib/asf
+INCLUDEPATH += src/taglib/flac
+INCLUDEPATH += src/taglib/mp4
+INCLUDEPATH += src/taglib/mpc
+INCLUDEPATH += src/taglib/mpeg
+INCLUDEPATH += src/taglib/mpeg/id3v1
+INCLUDEPATH += src/taglib/mpeg/id3v2
+INCLUDEPATH += src/taglib/ogg
+INCLUDEPATH += src/taglib/ogg/flac
+INCLUDEPATH += src/taglib/ogg/speex
+INCLUDEPATH += src/taglib/ogg/vorbis
+INCLUDEPATH += src/taglib/riff
+INCLUDEPATH += src/taglib/riff/aiff
+INCLUDEPATH += src/taglib/riff/wav
+INCLUDEPATH += src/taglib/trueaudio
+INCLUDEPATH += src/taglib/wavpack
 
 SOURCES += src/main.cpp\
         src/mainwindow.cpp \
@@ -26,7 +45,77 @@ SOURCES += src/main.cpp\
     src/busywidget.cpp \
     src/trackrenderer.cpp \
     src/config.cpp \
-    src/playlistdialog.cpp
+    src/playlistdialog.cpp \
+    src/taglib/tagunion.cpp \
+    src/taglib/tag.cpp \
+    src/taglib/fileref.cpp \
+    src/taglib/audioproperties.cpp \
+    src/taglib/ape/apetag.cpp \
+    src/taglib/ape/apeitem.cpp \
+    src/taglib/ape/apefooter.cpp \
+    src/taglib/asf/asftag.cpp \
+    src/taglib/asf/asfproperties.cpp \
+    src/taglib/asf/asffile.cpp \
+    src/taglib/asf/asfattribute.cpp \
+    src/taglib/flac/flacproperties.cpp \
+    src/taglib/flac/flacfile.cpp \
+    src/taglib/mp4/mp4tag.cpp \
+    src/taglib/mp4/mp4properties.cpp \
+    src/taglib/mp4/mp4item.cpp \
+    src/taglib/mp4/mp4file.cpp \
+    src/taglib/mp4/mp4coverart.cpp \
+    src/taglib/mp4/mp4atom.cpp \
+    src/taglib/mpc/mpcproperties.cpp \
+    src/taglib/mpc/mpcfile.cpp \
+    src/taglib/mpeg/xingheader.cpp \
+    src/taglib/mpeg/mpegproperties.cpp \
+    src/taglib/mpeg/mpegheader.cpp \
+    src/taglib/mpeg/mpegfile.cpp \
+    src/taglib/mpeg/id3v1/id3v1tag.cpp \
+    src/taglib/mpeg/id3v1/id3v1genres.cpp \
+    src/taglib/mpeg/id3v2/id3v2tag.cpp \
+    src/taglib/mpeg/id3v2/id3v2synchdata.cpp \
+    src/taglib/mpeg/id3v2/id3v2header.cpp \
+    src/taglib/mpeg/id3v2/id3v2framefactory.cpp \
+    src/taglib/mpeg/id3v2/id3v2frame.cpp \
+    src/taglib/mpeg/id3v2/id3v2footer.cpp \
+    src/taglib/mpeg/id3v2/id3v2extendedheader.cpp \
+    src/taglib/mpeg/id3v2/frames/urllinkframe.cpp \
+    src/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp \
+    src/taglib/mpeg/id3v2/frames/unknownframe.cpp \
+    src/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp \
+    src/taglib/mpeg/id3v2/frames/textidentificationframe.cpp \
+    src/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp \
+    src/taglib/mpeg/id3v2/frames/privateframe.cpp \
+    src/taglib/mpeg/id3v2/frames/popularimeterframe.cpp \
+    src/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp \
+    src/taglib/mpeg/id3v2/frames/commentsframe.cpp \
+    src/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp \
+    src/taglib/ogg/xiphcomment.cpp \
+    src/taglib/ogg/oggpageheader.cpp \
+    src/taglib/ogg/oggpage.cpp \
+    src/taglib/ogg/oggfile.cpp \
+    src/taglib/ogg/flac/oggflacfile.cpp \
+    src/taglib/ogg/speex/speexproperties.cpp \
+    src/taglib/ogg/speex/speexfile.cpp \
+    src/taglib/ogg/vorbis/vorbisproperties.cpp \
+    src/taglib/ogg/vorbis/vorbisfile.cpp \
+    src/taglib/riff/rifffile.cpp \
+    src/taglib/riff/aiff/aiffproperties.cpp \
+    src/taglib/riff/aiff/aifffile.cpp \
+    src/taglib/riff/wav/wavproperties.cpp \
+    src/taglib/riff/wav/wavfile.cpp \
+    src/taglib/toolkit/unicode.cpp \
+    src/taglib/toolkit/tstringlist.cpp \
+    src/taglib/toolkit/tstring.cpp \
+    src/taglib/toolkit/tfile.cpp \
+    src/taglib/toolkit/tdebug.cpp \
+    src/taglib/toolkit/tbytevectorlist.cpp \
+    src/taglib/toolkit/tbytevector.cpp \
+    src/taglib/trueaudio/trueaudioproperties.cpp \
+    src/taglib/trueaudio/trueaudiofile.cpp \
+    src/taglib/wavpack/wavpackproperties.cpp \
+    src/taglib/wavpack/wavpackfile.cpp
 
 HEADERS  += src/mainwindow.h \
                src/player/player.h \
@@ -45,7 +134,81 @@ HEADERS  += src/mainwindow.h \
     src/busywidget.h \
     src/trackrenderer.h \
     src/config.h \
-    src/playlistdialog.h
+    src/playlistdialog.h \
+    src/taglib/taglib_export.h \
+    src/taglib/tagunion.h \
+    src/taglib/tag.h \
+    src/taglib/fileref.h \
+    src/taglib/audioproperties.h \
+    src/taglib/ape/apetag.h \
+    src/taglib/ape/apeitem.h \
+    src/taglib/ape/apefooter.h \
+    src/taglib/asf/asftag.h \
+    src/taglib/asf/asfproperties.h \
+    src/taglib/asf/asffile.h \
+    src/taglib/asf/asfattribute.h \
+    src/taglib/flac/flacproperties.h \
+    src/taglib/flac/flacfile.h \
+    src/taglib/mp4/mp4tag.h \
+    src/taglib/mp4/mp4properties.h \
+    src/taglib/mp4/mp4item.h \
+    src/taglib/mp4/mp4file.h \
+    src/taglib/mp4/mp4coverart.h \
+    src/taglib/mp4/mp4atom.h \
+    src/taglib/mpc/mpcproperties.h \
+    src/taglib/mpc/mpcfile.h \
+    src/taglib/mpeg/xingheader.h \
+    src/taglib/mpeg/mpegproperties.h \
+    src/taglib/mpeg/mpegheader.h \
+    src/taglib/mpeg/mpegfile.h \
+    src/taglib/mpeg/id3v1/id3v1tag.h \
+    src/taglib/mpeg/id3v1/id3v1genres.h \
+    src/taglib/mpeg/id3v2/id3v2tag.h \
+    src/taglib/mpeg/id3v2/id3v2synchdata.h \
+    src/taglib/mpeg/id3v2/id3v2header.h \
+    src/taglib/mpeg/id3v2/id3v2framefactory.h \
+    src/taglib/mpeg/id3v2/id3v2frame.h \
+    src/taglib/mpeg/id3v2/id3v2footer.h \
+    src/taglib/mpeg/id3v2/id3v2extendedheader.h \
+    src/taglib/mpeg/id3v2/frames/urllinkframe.h \
+    src/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h \
+    src/taglib/mpeg/id3v2/frames/unknownframe.h \
+    src/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h \
+    src/taglib/mpeg/id3v2/frames/textidentificationframe.h \
+    src/taglib/mpeg/id3v2/frames/relativevolumeframe.h \
+    src/taglib/mpeg/id3v2/frames/privateframe.h \
+    src/taglib/mpeg/id3v2/frames/popularimeterframe.h \
+    src/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h \
+    src/taglib/mpeg/id3v2/frames/commentsframe.h \
+    src/taglib/mpeg/id3v2/frames/attachedpictureframe.h \
+    src/taglib/ogg/xiphcomment.h \
+    src/taglib/ogg/oggpageheader.h \
+    src/taglib/ogg/oggpage.h \
+    src/taglib/ogg/oggfile.h \
+    src/taglib/ogg/flac/oggflacfile.h \
+    src/taglib/ogg/speex/speexproperties.h \
+    src/taglib/ogg/speex/speexfile.h \
+    src/taglib/ogg/vorbis/vorbisproperties.h \
+    src/taglib/ogg/vorbis/vorbisfile.h \
+    src/taglib/riff/rifffile.h \
+    src/taglib/riff/aiff/aiffproperties.h \
+    src/taglib/riff/aiff/aifffile.h \
+    src/taglib/riff/wav/wavproperties.h \
+    src/taglib/riff/wav/wavfile.h \
+    src/taglib/toolkit/unicode.h \
+    src/taglib/toolkit/tstringlist.h \
+    src/taglib/toolkit/tstring.h \
+    src/taglib/toolkit/tmap.h \
+    src/taglib/toolkit/tlist.h \
+    src/taglib/toolkit/tfile.h \
+    src/taglib/toolkit/tdebug.h \
+    src/taglib/toolkit/tbytevectorlist.h \
+    src/taglib/toolkit/tbytevector.h \
+    src/taglib/toolkit/taglib.h \
+    src/taglib/trueaudio/trueaudioproperties.h \
+    src/taglib/trueaudio/trueaudiofile.h \
+    src/taglib/wavpack/wavpackproperties.h \
+    src/taglib/wavpack/wavpackfile.h
 
 FORMS    += src/ui/mainwindow.ui \
     src/ui/playerform.ui \
@@ -69,4 +232,14 @@ RESOURCES += \
 OTHER_FILES += \
     README \
     COPYING \
-    resources/someplayer.desktop
+    resources/someplayer.desktop \
+    src/taglib/taglib_config.h.in \
+    src/taglib/ape/ape-tag-format.txt \
+    src/taglib/mpeg/id3v2/id3v2.4.0-structure.txt \
+    src/taglib/mpeg/id3v2/id3v2.4.0-frames.txt \
+    src/taglib/mpeg/id3v2/id3v2.3.0.txt \
+    src/taglib/mpeg/id3v2/id3v2.2.0.txt \
+    src/taglib/toolkit/tmap.tcc \
+    src/taglib/toolkit/tlist.tcc \
+    AUTHORS.TagLib \
+    COPYING.LGPL
index ace5a7d..c615376 100644 (file)
 
 #include "busywidget.h"
 #include "ui_busywidget.h"
+#include <QDebug>
 
 BusyWidget::BusyWidget(QWidget *parent) :
     QWidget(parent),
     ui(new Ui::BusyWidget)
 {
     ui->setupUi(this);
+    ui->progressBar->setValue(0);
 }
 
 BusyWidget::~BusyWidget()
@@ -35,3 +37,12 @@ BusyWidget::~BusyWidget()
 void BusyWidget::setText(QString text) {
        ui->label->setText(text);
 }
+
+void BusyWidget::setMax(int max) {
+       ui->progressBar->setMaximum(max);
+       ui->progressBar->setValue(0);
+}
+
+void BusyWidget::tick() {
+       ui->progressBar->setValue(ui->progressBar->value()+1);
+}
index 9439f8d..86ab387 100644 (file)
 #include <QWidget>
 
 namespace Ui {
-    class BusyWidget;
+       class BusyWidget;
 }
 
 class BusyWidget : public QWidget
 {
-    Q_OBJECT
+       Q_OBJECT
 
 public:
-    explicit BusyWidget(QWidget *parent = 0);
-    ~BusyWidget();
+       explicit BusyWidget(QWidget *parent = 0);
+       ~BusyWidget();
        void setText(QString text);
+public slots:
+       void setMax(int);
+       void tick();
 
 private:
-    Ui::BusyWidget *ui;
+       Ui::BusyWidget *ui;
 };
 
 #endif // BUSYWIDGET_H
index 58d7feb..562afd5 100644 (file)
@@ -30,9 +30,9 @@ Library::Library(QString databasePath, QString playlistsPath) : QObject(0) {
        _playlist_storage = new FileStorage(playlistsPath);
        _scanner = new MediaScanner();
        _resolver = new TagResolver(this);
-       connect(_scanner, SIGNAL(scanFinish(QStringList)), _resolver, SLOT(decode(QStringList)));
+       connect(_scanner, SIGNAL(scanFinish(QStringList)), this, SLOT(_scanned(QStringList)));
        connect(_resolver, SIGNAL(done()), this, SIGNAL(done()));
-       connect(_resolver, SIGNAL(decoded(Track)), this, SLOT(addTrack(Track)));
+       connect(_resolver, SIGNAL(decoded(Track)), this, SLOT(_decoded(Track)));
 }
 
 Library::~Library() {
@@ -132,3 +132,13 @@ Playlist Library::getCurrentPlaylist() {
 void Library::saveCurrentPlaylist(const Playlist &playlist) {
        _playlist_storage->saveCurrentPlaylist(playlist);
 }
+
+void Library::_decoded(Track track) {
+       emit trackAdded();
+       addTrack(track);
+}
+
+void Library::_scanned(QStringList files) {
+       emit addingTracks(files.count());
+       _resolver->decode(files);
+}
index b7e674b..9268609 100644 (file)
@@ -72,6 +72,8 @@ namespace SomePlayer {
                signals:
                        void done();
                        void busy(QString);
+                       void addingTracks(int);
+                       void trackAdded();
 
                private:
                        DbStorage *_library_storage;
@@ -79,6 +81,10 @@ namespace SomePlayer {
                        MediaScanner *_scanner;
                        TagResolver *_resolver;
 
+               private slots:
+                       void _scanned(QStringList);
+                       void _decoded(Track);
+
                public slots:
                        void removeTrack(Track);
                        void addTrack(Track);
index a7d59d0..424023f 100644 (file)
@@ -58,6 +58,8 @@ MainWindow::MainWindow(QWidget *parent) :
        connect(clear_playlist, SIGNAL(triggered()), this, SLOT(_clear_current_playlist()));
        connect(add_files, SIGNAL(triggered()), this, SLOT(_add_files()));
        connect(_library, SIGNAL(done()), this, SLOT(library()));
+       connect(_library, SIGNAL(addingTracks(int)), _busy_widget, SLOT(setMax(int)));
+       connect(_library, SIGNAL(trackAdded()), _busy_widget, SLOT(tick()));
        connect(_library_form, SIGNAL(done()), this, SLOT(library()));
        connect(_library_form, SIGNAL(busy(QString)), this, SLOT(showBusyWidget(QString)));
        connect(ui->searchButton, SIGNAL(clicked()), this, SLOT(_toggle_search_line()));
index c026fa6..1b84640 100644 (file)
@@ -27,7 +27,7 @@ using namespace SomePlayer::Storage;
 MediaScanner::MediaScanner(QObject *parent) :
                QThread(parent), _stopped(false), _initialized(false)
 {
-       REGISTERED_FILE_EXTENSIONS << "mp3" << "flac" << "wma" << "acc";
+       REGISTERED_FILE_EXTENSIONS << "mp3" << "flac" << "wma" << "acc" << "ogg";
 }
 
 void MediaScanner::run() {
index 6ecab29..2008b4b 100644 (file)
@@ -47,5 +47,6 @@ namespace SomePlayer {
 #include "config.h"
 
 #define _DYNAMIC_PLAYLIST_MAX_COUNT_ 50
+#define NDEBUG
 
 #endif
diff --git a/src/taglib/ape/ape-tag-format.txt b/src/taglib/ape/ape-tag-format.txt
new file mode 100644 (file)
index 0000000..21ff1c8
--- /dev/null
@@ -0,0 +1,170 @@
+================================================================================
+= APE Tag Specification, Version 2.000
+================================================================================
+
+Original Content     (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de>
+Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org>
+
+================================================================================
+= Contents
+================================================================================
+
+1   - APE Tag General Structure
+2   - APE Tag Header / Footer Format
+3   - APE Tag Flags
+4   - APE Tag Item Format
+5   - APE Tag Item Supported Keys
+6   - APE Tag Item Content
+7   - Data Types
+7.1 - Data Types / UTF-8
+7.2 - Data Types / Dates
+7.3 - Data Types / Timestamps
+
+================================================================================
+= 1 - APE Tag General Structure
+================================================================================
+
+Member of Basic Components of SV8 Stream Note:
+
+It is strongly recommended that the data size be stored in the tags.  The size
+should normally be in the roughly one kilobyte, never more than 8 kilobytes.
+
+Larger data should be stored externally using link entries.  Linked data is much
+easier to process by normal programs, so for instance JPEG data should not be
+included inside the audio file.
+
+APE Tag Version 2.000 (with header, recommended):
+
+/================================\
+| APE Tag Header    | 32 bytes   |
+|-------------------|------------|
+| APE Tag Item 1    | > 10 bytes |
+| APE Tag Item 2    | > 10 bytes |
+| APE Tag Item n-1  | > 10 bytes |
+| APE Tag Item n    | > 10 bytes |
+|-------------------|------------|
+| APE Tag Footer    | 32 bytes   |
+\================================/
+
+
+APE tag items should be sorted ascending by size.  When streaming, parts of the
+APE tag may be dropped to reduce the danger of drop outs between tracks.  This
+is not required, but is strongly recommended.  It would be desirable for the i
+tems to be sorted by importance / size, but this is not feasible.  This
+convention should only be broken when adding less important small items and it
+is not desirable to rewrite the entire tag.  An APE tag at the end of a file
+(the recommended location) must have at least a footer; an APE tag at the
+beginning of a file (strongly discouraged) must have at least a header.
+
+APE Tag Version 1.000 (without header, deprecated)
+
+/================================\
+| APE Tag Item 1    | > 10 bytes |
+| APE Tag Item 2    | > 10 bytes |
+| APE Tag Item n-1  | > 10 bytes |
+| APE Tag Item n    | > 10 bytes |
+|-------------------|------------|
+| APE Tag Footer    | 32 bytes   |
+\================================/
+
+================================================================================
+= 2 - APE Tag Header / Footer Format
+================================================================================
+
+Contains number, length and attributes of all tag items
+
+Header and Footer are different in 1 bit in the Tags Flags to distinguish
+between them.
+
+Member of APE Tag 2.0
+
+/===========================================================================\
+| Preamble       | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' }     |
+|----------------|---------|------------------------------------------------|
+| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000     |
+|----------------|---------|------------------------------------------------|
+| Tag Size       | 4 bytes | Tag size in bytes including footer and all tag |
+|                |         | items excluding the header (for 1.000          |
+|                |         | compatibility)                                 |
+|----------------|---------|------------------------------------------------|
+| Item Count     | 4 bytes | Number of items in the tag                     |
+|----------------|---------|------------------------------------------------|
+| Tag Flags      | 4 bytes | Global flags                                   |
+|----------------|---------|------------------------------------------------|
+| Reserved       | 8 bytes | Must be zeroed                                 |
+\===========================================================================/
+
+================================================================================
+= 3 - APE Tag Flags
+================================================================================
+
+The general flag structure for either items or headers / footers is the same.
+Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are
+item specific.
+
+Note: APE Tags from Version 1.0 do not use any of the following.  All flags in
+that version are zeroed and ignored when reading.
+
+/=================================================================\
+| Contains Header | Bit 31      | 1 - has header | 0 - no header  |
+|-----------------|-------------|---------------------------------|
+| Contains Footer | Bit 30      | 1 - has footer | 0 - no footer  |
+|-----------------|-------------|---------------------------------|
+| Is Header       | Bit 29      | 1 - is header  | 0 - is footer  |
+|-----------------|-------------|---------------------------------|
+| Undefined       | Bits 28 - 3 | Undefined, must be zeroed       |
+|-----------------|-------------|---------------------------------|
+| Encoding        | Bits 2 - 1  | 00 - UTF-8                      |
+|                 |             | 01 - Binary Data *              |
+|                 |             | 10 - External Reference **      |
+|                 |             | 11 - Reserved                   |
+|-----------------|-------------|---------------------------------|
+| Read Only       | Bit 0       | 1 - read only  | 0 - read/write |
+\=================================================================/
+
+ (*) Should be ignored by tools for editing text values
+(**) Allowed external reference formats:
+     - http://host/directory/filename.ext
+     - ftp://host/directory/filename.ext
+     - filename.ext
+     - /directory/filename.ext
+     - DRIVE:/directory/filename.ext
+
+     Note: External references are also UTF-8 encoded.
+
+================================================================================
+= 4 - APE Tag Item Format
+================================================================================
+
+APE Tag Items are stored as key-value pairs.  APE Tags Item Key are case
+sensitive, however it is illegal to use keys which only differ in case and
+it is recommended that tag reading not be case sensitive.
+
+Every key can only occur (at most) once. It is not possible to repeat a key
+to signify updated contents.
+
+Tags can be partially or completely repeated in the streaming format.  This
+makes it possible to display an artist and / or title if it was missed at the
+beginning of the stream.  It is recommended that the important information like
+artist, album and title should occur approximately every 2 minutes in the
+stream and again 5 to 10 seconds before the end.  However, care should be tak
+en not to replicate this information too often or during passages with high
+bitrate demands to avoid unnecessary drop-outs.
+
+/==============================================================================\
+| Content Size   | 4 bytes       | Length of the value in bytes                |
+|----------------|---------------|---------------------------------------------|
+| Flags          | 4 bytes       | Item flags                                  |
+|----------------|---------------|---------------------------------------------|
+| Key            | 2 - 255 bytes | Item key                                    |
+|----------------|---------------|---------------------------------------------|
+| Key Terminator | 1 byte        | Null byte that indicates the end of the key |
+|----------------|---------------|---------------------------------------------|
+| Value          | variable      | Content (formatted according to the flags)  |
+\==============================================================================/
+
+================================================================================
+
+Sections 5 - 7 haven't yet been converted from:
+
+http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
diff --git a/src/taglib/ape/apefooter.cpp b/src/taglib/ape/apefooter.cpp
new file mode 100644 (file)
index 0000000..da6494b
--- /dev/null
@@ -0,0 +1,236 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+                           (C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp)
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <iostream>
+#include <bitset>
+
+#include <tstring.h>
+#include <tdebug.h>
+
+#include "apefooter.h"
+
+using namespace TagLib;
+using namespace APE;
+
+class Footer::FooterPrivate
+{
+public:
+  FooterPrivate() : version(0),
+                    footerPresent(true),
+                    headerPresent(false),
+                    isHeader(false),
+                    itemCount(0),
+                    tagSize(0) {}
+
+  ~FooterPrivate() {}
+
+  uint version;
+
+  bool footerPresent;
+  bool headerPresent;
+
+  bool isHeader;
+
+  uint itemCount;
+  uint tagSize;
+
+  static const uint size = 32;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// static members
+////////////////////////////////////////////////////////////////////////////////
+
+TagLib::uint Footer::size()
+{
+  return FooterPrivate::size;
+}
+
+ByteVector Footer::fileIdentifier()
+{
+  return ByteVector::fromCString("APETAGEX");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+Footer::Footer()
+{
+  d = new FooterPrivate;
+}
+
+Footer::Footer(const ByteVector &data)
+{
+  d = new FooterPrivate;
+  parse(data);
+}
+
+Footer::~Footer()
+{
+  delete d;
+}
+
+TagLib::uint Footer::version() const
+{
+  return d->version;
+}
+
+bool Footer::headerPresent() const
+{
+  return d->headerPresent;
+}
+
+bool Footer::footerPresent() const
+{
+  return d->footerPresent;
+}
+
+bool Footer::isHeader() const
+{
+  return d->isHeader;
+}
+
+void Footer::setHeaderPresent(bool b) const
+{
+  d->headerPresent = b;
+}
+
+TagLib::uint Footer::itemCount() const
+{
+  return d->itemCount;
+}
+
+void Footer::setItemCount(uint s)
+{
+  d->itemCount = s;
+}
+
+TagLib::uint Footer::tagSize() const
+{
+  return d->tagSize;
+}
+
+TagLib::uint Footer::completeTagSize() const
+{
+  if(d->headerPresent)
+    return d->tagSize + d->size;
+  else
+    return d->tagSize;
+}
+
+void Footer::setTagSize(uint s)
+{
+  d->tagSize = s;
+}
+
+void Footer::setData(const ByteVector &data)
+{
+  parse(data);
+}
+
+ByteVector Footer::renderFooter() const
+{
+    return render(false);
+}
+
+ByteVector Footer::renderHeader() const
+{
+    if (!d->headerPresent) return ByteVector();
+
+    return render(true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected members
+////////////////////////////////////////////////////////////////////////////////
+
+void Footer::parse(const ByteVector &data)
+{
+  if(data.size() < size())
+    return;
+
+  // The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".
+
+  // Read the version number
+
+  d->version = data.mid(8, 4).toUInt(false);
+
+  // Read the tag size
+
+  d->tagSize = data.mid(12, 4).toUInt(false);
+
+  // Read the item count
+
+  d->itemCount = data.mid(16, 4).toUInt(false);
+
+  // Read the flags
+
+  std::bitset<32> flags(data.mid(20, 4).toUInt(false));
+
+  d->headerPresent = flags[31];
+  d->footerPresent = !flags[30];
+  d->isHeader = flags[29];
+
+}
+
+ByteVector Footer::render(bool isHeader) const
+{
+  ByteVector v;
+
+  // add the file identifier -- "APETAGEX"
+
+  v.append(fileIdentifier());
+
+  // add the version number -- we always render a 2.000 tag regardless of what
+  // the tag originally was.
+
+  v.append(ByteVector::fromUInt(2000, false));
+
+  // add the tag size
+
+  v.append(ByteVector::fromUInt(d->tagSize, false));
+
+  // add the item count
+
+  v.append(ByteVector::fromUInt(d->itemCount, false));
+
+  // render and add the flags
+
+  std::bitset<32> flags;
+
+  flags[31] = d->headerPresent;
+  flags[30] = false; // footer is always present
+  flags[29] = isHeader;
+
+  v.append(ByteVector::fromUInt(flags.to_ulong(), false));
+
+  // add the reserved 64bit
+
+  v.append(ByteVector::fromLongLong(0));
+
+  return v;
+}
diff --git a/src/taglib/ape/apefooter.h b/src/taglib/ape/apefooter.h
new file mode 100644 (file)
index 0000000..f0d921f
--- /dev/null
@@ -0,0 +1,173 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_APEFOOTER_H
+#define TAGLIB_APEFOOTER_H
+
+#include "tbytevector.h"
+#include "taglib_export.h"
+
+namespace TagLib {
+
+  namespace APE {
+
+    //! An implementation of APE footers
+
+    /*!
+     * This class implements APE footers (and headers). It attempts to follow, both
+     * semantically and programatically, the structure specified in
+     * the APE v2.0 standard.  The API is based on the properties of APE footer and
+     * headers specified there.
+     */
+
+    class TAGLIB_EXPORT Footer
+    {
+    public:
+      /*!
+       * Constructs an empty APE footer.
+       */
+      Footer();
+
+      /*!
+       * Constructs an APE footer based on \a data.  parse() is called
+       * immediately.
+       */
+      Footer(const ByteVector &data);
+
+      /*!
+       * Destroys the footer.
+       */
+      virtual ~Footer();
+
+      /*!
+       * Returns the version number.  (Note: This is the 1000 or 2000.)
+       */
+      uint version() const;
+
+      /*!
+       * Returns true if a header is present in the tag.
+       */
+      bool headerPresent() const;
+
+      /*!
+       * Returns true if a footer is present in the tag.
+       */
+      bool footerPresent() const;
+
+      /*!
+       * Returns true this is actually the header.
+       */
+      bool isHeader() const;
+
+      /*!
+       * Sets whether the header should be rendered or not
+       */
+      void setHeaderPresent(bool b) const;
+
+      /*!
+       * Returns the number of items in the tag.
+       */
+      uint itemCount() const;
+
+      /*!
+       * Set the item count to \a s.
+       * \see itemCount()
+       */
+      void setItemCount(uint s);
+
+      /*!
+       * Returns the tag size in bytes.  This is the size of the frame content and footer.
+       * The size of the \e entire tag will be this plus the header size, if present.
+       *
+       * \see completeTagSize()
+       */
+      uint tagSize() const;
+
+      /*!
+       * Returns the tag size, including if present, the header
+       * size.
+       *
+       * \see tagSize()
+       */
+      uint completeTagSize() const;
+
+      /*!
+       * Set the tag size to \a s.
+       * \see tagSize()
+       */
+      void setTagSize(uint s);
+
+      /*!
+       * Returns the size of the footer.  Presently this is always 32 bytes.
+       */
+      static uint size();
+
+      /*!
+       * Returns the string used to identify an APE tag inside of a file.
+       * Presently this is always "APETAGEX".
+       */
+      static ByteVector fileIdentifier();
+
+      /*!
+       * Sets the data that will be used as the footer.  32 bytes,
+       * starting from \a data will be used.
+       */
+      void setData(const ByteVector &data);
+
+      /*!
+       * Renders the footer back to binary format.
+       */
+      ByteVector renderFooter() const;
+
+      /*!
+       * Renders the header corresponding to the footer. If headerPresent is
+       * set to false, it returns an empty ByteVector.
+       */
+      ByteVector renderHeader() const;
+
+    protected:
+      /*!
+       * Called by setData() to parse the footer data.  It makes this information
+       * available through the public API.
+       */
+      void parse(const ByteVector &data);
+
+      /*!
+       * Called by renderFooter and renderHeader
+       */
+      ByteVector render(bool isHeader) const;
+
+    private:
+      Footer(const Footer &);
+      Footer &operator=(const Footer &);
+
+      class FooterPrivate;
+      FooterPrivate *d;
+    };
+
+  }
+}
+
+#endif
diff --git a/src/taglib/ape/apeitem.cpp b/src/taglib/ape/apeitem.cpp
new file mode 100644 (file)
index 0000000..77a9ca0
--- /dev/null
@@ -0,0 +1,230 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.com
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <tbytevectorlist.h>
+#include <tdebug.h>
+
+#include "apeitem.h"
+
+using namespace TagLib;
+using namespace APE;
+
+class APE::Item::ItemPrivate
+{
+public:
+  ItemPrivate() : type(Text), readOnly(false) {}
+
+  Item::ItemTypes type;
+  String key;
+  ByteVector value;
+  StringList text;
+  bool readOnly;
+};
+
+APE::Item::Item()
+{
+  d = new ItemPrivate;
+}
+
+APE::Item::Item(const String &key, const String &value)
+{
+  d = new ItemPrivate;
+  d->key = key;
+  d->text.append(value);
+}
+
+APE::Item::Item(const String &key, const StringList &values)
+{
+  d = new ItemPrivate;
+  d->key = key;
+  d->text = values;
+}
+
+APE::Item::Item(const Item &item)
+{
+  d = new ItemPrivate(*item.d);
+}
+
+APE::Item::~Item()
+{
+  delete d;
+}
+
+Item &APE::Item::operator=(const Item &item)
+{
+  delete d;
+  d = new ItemPrivate(*item.d);
+  return *this;
+}
+
+void APE::Item::setReadOnly(bool readOnly)
+{
+  d->readOnly = readOnly;
+}
+
+bool APE::Item::isReadOnly() const
+{
+  return d->readOnly;
+}
+
+void APE::Item::setType(APE::Item::ItemTypes val)
+{
+  d->type = val;
+}
+
+APE::Item::ItemTypes APE::Item::type() const
+{
+  return d->type;
+}
+
+String APE::Item::key() const
+{
+  return d->key;
+}
+
+ByteVector APE::Item::value() const
+{
+  // This seems incorrect as it won't be actually rendering the value to keep it
+  // up to date.
+
+  return d->value;
+}
+
+void APE::Item::setKey(const String &key)
+{
+    d->key = key;
+}
+
+void APE::Item::setValue(const String &value)
+{
+    d->text = value;
+}
+
+void APE::Item::setValues(const StringList &value)
+{
+    d->text = value;
+}
+
+void APE::Item::appendValue(const String &value)
+{
+    d->text.append(value);
+}
+
+void APE::Item::appendValues(const StringList &values)
+{
+    d->text.append(values);
+}
+
+int APE::Item::size() const
+{
+  return 8 + d->key.size() + 1 + d->value.size();
+}
+
+StringList APE::Item::toStringList() const
+{
+  return d->text;
+}
+
+StringList APE::Item::values() const
+{
+  return d->text;
+}
+
+String APE::Item::toString() const
+{
+  return isEmpty() ? String::null : d->text.front();
+}
+
+bool APE::Item::isEmpty() const
+{
+  switch(d->type) {
+    case Text:
+    case Binary:
+      if(d->text.isEmpty())
+        return true;
+      if(d->text.size() == 1 && d->text.front().isEmpty())
+        return true;
+      return false;
+    case Locator:
+      return d->value.isEmpty();
+    default:
+      return false;
+  }
+}
+
+void APE::Item::parse(const ByteVector &data)
+{
+  // 11 bytes is the minimum size for an APE item
+
+  if(data.size() < 11) {
+    debug("APE::Item::parse() -- no data in item");
+    return;
+  }
+
+  uint valueLength  = data.mid(0, 4).toUInt(false);
+  uint flags        = data.mid(4, 4).toUInt(false);
+
+  d->key = String(data.mid(8), String::UTF8);
+
+  d->value = data.mid(8 + d->key.size() + 1, valueLength);
+
+  setReadOnly(flags & 1);
+  setType(ItemTypes((flags >> 1) & 3));
+
+  if(int(d->type) < 2)
+    d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
+}
+
+ByteVector APE::Item::render() const
+{
+  ByteVector data;
+  TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
+  ByteVector value;
+
+  if(isEmpty())
+    return data;
+
+  if(d->type == Text) {
+    StringList::ConstIterator it = d->text.begin();
+
+    value.append(it->data(String::UTF8));
+    it++;
+    for(; it != d->text.end(); ++it) {
+      value.append('\0');
+      value.append(it->data(String::UTF8));
+    }
+    d->value = value;
+  }
+  else
+    value.append(d->value);
+
+  data.append(ByteVector::fromUInt(value.size(), false));
+  data.append(ByteVector::fromUInt(flags, false));
+  data.append(d->key.data(String::UTF8));
+  data.append(ByteVector('\0'));
+  data.append(value);
+
+  return data;
+}
diff --git a/src/taglib/ape/apeitem.h b/src/taglib/ape/apeitem.h
new file mode 100644 (file)
index 0000000..8558bb3
--- /dev/null
@@ -0,0 +1,204 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_APEITEM_H
+#define TAGLIB_APEITEM_H
+
+#include "tbytevector.h"
+#include "tstring.h"
+#include "tstringlist.h"
+
+namespace TagLib {
+
+  namespace APE {
+
+    //! An implementation of APE-items
+
+    /*!
+     * This class provides the features of items in the APEv2 standard.
+     */
+    class TAGLIB_EXPORT Item
+    {
+    public:
+      /*!
+       * Enum of types an Item can have. The value of 3 is reserved.
+       */
+      enum ItemTypes {
+        //! Item contains text information coded in UTF-8
+        Text = 0,
+        //! Item contains binary information
+        Binary = 1,
+        //! Item is a locator of external stored information
+        Locator = 2
+      };
+      /*!
+       * Constructs an empty item.
+       */
+      Item();
+
+      /*!
+       * Constructs an item with \a key and \a value.
+       */
+      // BIC: Remove this, StringList has a constructor from a single string
+      Item(const String &key, const String &value);
+
+      /*!
+       * Constructs an item with \a key and \a values.
+       */
+      Item(const String &key, const StringList &values);
+
+      /*!
+       * Construct an item as a copy of \a item.
+       */
+      Item(const Item &item);
+
+      /*!
+       * Destroys the item.
+       */
+      virtual ~Item();
+
+      /*!
+       * Copies the contents of \a item into this item.
+       */
+      Item &operator=(const Item &item);
+
+      /*!
+       * Returns the key.
+       */
+      String key() const;
+
+      /*!
+       * Returns the binary value.
+       *
+       * \deprecated This will be removed in the next binary incompatible version
+       * as it is not kept in sync with the things that are set using setValue()
+       * and friends.
+       */
+      ByteVector value() const;
+
+      /*!
+       * Sets the key for the item to \a key.
+       */
+      void setKey(const String &key);
+
+      /*!
+       * Sets the value of the item to \a value and clears any previous contents.
+       *
+       * \see toString()
+       */
+      void setValue(const String &value);
+
+      /*!
+       * Sets the value of the item to the list of values in \a value and clears
+       * any previous contents.
+       *
+       * \see toStringList()
+       */
+      void setValues(const StringList &values);
+
+      /*!
+       * Appends \a value to create (or extend) the current list of values.
+       *
+       * \see toString()
+       */
+      void appendValue(const String &value);
+
+      /*!
+       * Appends \a values to extend the current list of values.
+       *
+       * \see toStringList()
+       */
+      void appendValues(const StringList &values);
+
+      /*!
+       * Returns the size of the full item.
+       */
+      int size() const;
+
+      /*!
+       * Returns the value as a single string. In case of multiple strings,
+       * the first is returned.
+       */
+      String toString() const;
+
+      /*!
+       * \deprecated
+       * \see values
+       */
+      StringList toStringList() const;
+
+      /*!
+       * Returns the list of values.
+       */
+      StringList values() const;
+
+      /*!
+       * Render the item to a ByteVector.
+       */
+      ByteVector render() const;
+
+      /*!
+       * Parse the item from the ByteVector \a data.
+       */
+      void parse(const ByteVector& data);
+
+      /*!
+       * Set the item to read-only.
+       */
+      void setReadOnly(bool readOnly);
+
+      /*!
+       * Return true if the item is read-only.
+       */
+      bool isReadOnly() const;
+
+      /*!
+       * Sets the type of the item to \a type.
+       *
+       * \see ItemTypes
+       */
+      void setType(ItemTypes type);
+
+      /*!
+       * Returns the type of the item.
+       */
+      ItemTypes type() const;
+
+      /*!
+       * Returns if the item has any real content.
+       */
+      bool isEmpty() const;
+
+    private:
+      class ItemPrivate;
+      ItemPrivate *d;
+    };
+  }
+
+}
+
+#endif
+
+
diff --git a/src/taglib/ape/apetag.cpp b/src/taglib/ape/apetag.cpp
new file mode 100644 (file)
index 0000000..1c38d2b
--- /dev/null
@@ -0,0 +1,266 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.com
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef __SUNPRO_CC
+// Sun Studio finds multiple specializations of Map because
+// it considers specializations with and without class types
+// to be different; this define forces Map to use only the
+// specialization with the class keyword.
+#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
+#endif
+
+#include <tfile.h>
+#include <tstring.h>
+#include <tmap.h>
+
+#include "apetag.h"
+#include "apefooter.h"
+#include "apeitem.h"
+
+using namespace TagLib;
+using namespace APE;
+
+class APE::Tag::TagPrivate
+{
+public:
+  TagPrivate() : file(0), footerLocation(-1), tagLength(0) {}
+
+  File *file;
+  long footerLocation;
+  long tagLength;
+
+  Footer footer;
+
+  ItemListMap itemListMap;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public methods
+////////////////////////////////////////////////////////////////////////////////
+
+APE::Tag::Tag() : TagLib::Tag()
+{
+  d = new TagPrivate;
+}
+
+APE::Tag::Tag(File *file, long footerLocation) : TagLib::Tag()
+{
+  d = new TagPrivate;
+  d->file = file;
+  d->footerLocation = footerLocation;
+
+  read();
+}
+
+APE::Tag::~Tag()
+{
+  delete d;
+}
+
+ByteVector APE::Tag::fileIdentifier()
+{
+  return ByteVector::fromCString("APETAGEX");
+}
+
+String APE::Tag::title() const
+{
+  if(d->itemListMap["TITLE"].isEmpty())
+    return String::null;
+  return d->itemListMap["TITLE"].toString();
+}
+
+String APE::Tag::artist() const
+{
+  if(d->itemListMap["ARTIST"].isEmpty())
+    return String::null;
+  return d->itemListMap["ARTIST"].toString();
+}
+
+String APE::Tag::album() const
+{
+  if(d->itemListMap["ALBUM"].isEmpty())
+    return String::null;
+  return d->itemListMap["ALBUM"].toString();
+}
+
+String APE::Tag::comment() const
+{
+  if(d->itemListMap["COMMENT"].isEmpty())
+    return String::null;
+  return d->itemListMap["COMMENT"].toString();
+}
+
+String APE::Tag::genre() const
+{
+  if(d->itemListMap["GENRE"].isEmpty())
+    return String::null;
+  return d->itemListMap["GENRE"].toString();
+}
+
+TagLib::uint APE::Tag::year() const
+{
+  if(d->itemListMap["YEAR"].isEmpty())
+    return 0;
+  return d->itemListMap["YEAR"].toString().toInt();
+}
+
+TagLib::uint APE::Tag::track() const
+{
+  if(d->itemListMap["TRACK"].isEmpty())
+    return 0;
+  return d->itemListMap["TRACK"].toString().toInt();
+}
+
+void APE::Tag::setTitle(const String &s)
+{
+  addValue("TITLE", s, true);
+}
+
+void APE::Tag::setArtist(const String &s)
+{
+  addValue("ARTIST", s, true);
+}
+
+void APE::Tag::setAlbum(const String &s)
+{
+  addValue("ALBUM", s, true);
+}
+
+void APE::Tag::setComment(const String &s)
+{
+  addValue("COMMENT", s, true);
+}
+
+void APE::Tag::setGenre(const String &s)
+{
+  addValue("GENRE", s, true);
+}
+
+void APE::Tag::setYear(uint i)
+{
+  if(i <= 0)
+    removeItem("YEAR");
+  else
+    addValue("YEAR", String::number(i), true);
+}
+
+void APE::Tag::setTrack(uint i)
+{
+  if(i <= 0)
+    removeItem("TRACK");
+  else
+    addValue("TRACK", String::number(i), true);
+}
+
+APE::Footer *APE::Tag::footer() const
+{
+  return &d->footer;
+}
+
+const APE::ItemListMap& APE::Tag::itemListMap() const
+{
+  return d->itemListMap;
+}
+
+void APE::Tag::removeItem(const String &key)
+{
+  Map<const String, Item>::Iterator it = d->itemListMap.find(key.upper());
+  if(it != d->itemListMap.end())
+    d->itemListMap.erase(it);
+}
+
+void APE::Tag::addValue(const String &key, const String &value, bool replace)
+{
+  if(replace)
+    removeItem(key);
+  if(!value.isEmpty()) {
+    if(d->itemListMap.contains(key) || !replace)
+      d->itemListMap[key.upper()].appendValue(value);
+    else
+      setItem(key, Item(key, value));
+  }
+}
+
+void APE::Tag::setItem(const String &key, const Item &item)
+{
+  d->itemListMap.insert(key.upper(), item);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected methods
+////////////////////////////////////////////////////////////////////////////////
+
+void APE::Tag::read()
+{
+  if(d->file && d->file->isValid()) {
+
+    d->file->seek(d->footerLocation);
+    d->footer.setData(d->file->readBlock(Footer::size()));
+
+    if(d->footer.tagSize() <= Footer::size() ||
+       d->footer.tagSize() > uint(d->file->length()))
+      return;
+
+    d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
+    parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
+  }
+}
+
+ByteVector APE::Tag::render() const
+{
+  ByteVector data;
+  uint itemCount = 0;
+
+  {
+    for(Map<const String, Item>::ConstIterator it = d->itemListMap.begin();
+        it != d->itemListMap.end(); ++it)
+    {
+      data.append(it->second.render());
+      itemCount++;
+    }
+  }
+
+  d->footer.setItemCount(itemCount);
+  d->footer.setTagSize(data.size() + Footer::size());
+  d->footer.setHeaderPresent(true);
+
+  return d->footer.renderHeader() + data + d->footer.renderFooter();
+}
+
+void APE::Tag::parse(const ByteVector &data)
+{
+  uint pos = 0;
+
+  // 11 bytes is the minimum size for an APE item
+
+  for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
+    APE::Item item;
+    item.parse(data.mid(pos));
+
+    d->itemListMap.insert(item.key().upper(), item);
+
+    pos += item.size();
+  }
+}
diff --git a/src/taglib/ape/apetag.h b/src/taglib/ape/apetag.h
new file mode 100644 (file)
index 0000000..03a3c91
--- /dev/null
@@ -0,0 +1,162 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_APETAG_H
+#define TAGLIB_APETAG_H
+
+#include "tag.h"
+#include "tbytevector.h"
+#include "tmap.h"
+#include "tstring.h"
+#include "taglib_export.h"
+
+#include "apeitem.h"
+
+namespace TagLib {
+
+  class File;
+
+  //! An implementation of the APE tagging format
+
+  namespace APE {
+
+    class Footer;
+
+    /*!
+     * A mapping between a list of item names, or keys, and the associated item.
+     *
+     * \see APE::Tag::itemListMap()
+     */
+    typedef Map<const String, Item> ItemListMap;
+
+
+    //! An APE tag implementation
+
+    class TAGLIB_EXPORT Tag : public TagLib::Tag
+    {
+    public:
+      /*!
+       * Create an APE tag with default values.
+       */
+      Tag();
+
+      /*!
+       * Create an APE tag and parse the data in \a file with APE footer at
+       * \a tagOffset.
+       */
+      Tag(File *file, long footerLocation);
+
+      /*!
+       * Destroys this Tag instance.
+       */
+      virtual ~Tag();
+
+      /*!
+       * Renders the in memory values to a ByteVector suitable for writing to
+       * the file.
+       */
+      ByteVector render() const;
+
+      /*!
+       * Returns the string "APETAGEX" suitable for usage in locating the tag in a
+       * file.
+       */
+      static ByteVector fileIdentifier();
+
+      // Reimplementations.
+
+      virtual String title() const;
+      virtual String artist() const;
+      virtual String album() const;
+      virtual String comment() const;
+      virtual String genre() const;
+      virtual uint year() const;
+      virtual uint track() const;
+
+      virtual void setTitle(const String &s);
+      virtual void setArtist(const String &s);
+      virtual void setAlbum(const String &s);
+      virtual void setComment(const String &s);
+      virtual void setGenre(const String &s);
+      virtual void setYear(uint i);
+      virtual void setTrack(uint i);
+
+      /*!
+       * Returns a pointer to the tag's footer.
+       */
+      Footer *footer() const;
+
+      /*!
+       * Returns a reference to the item list map.  This is an ItemListMap of
+       * all of the items in the tag.
+       *
+       * This is the most powerfull structure for accessing the items of the tag.
+       *
+       * \warning You should not modify this data structure directly, instead
+       * use setItem() and removeItem().
+       */
+      const ItemListMap &itemListMap() const;
+
+      /*!
+       * Removes the \a key item from the tag
+       */
+      void removeItem(const String &key);
+
+      /*!
+       * Adds to the item specified by \a key the data \a value.  If \a replace
+       * is true, then all of the other values on the same key will be removed
+       * first.
+       */
+      void addValue(const String &key, const String &value, bool replace = true);
+
+      /*!
+       * Sets the \a key item to the value of \a item. If an item with the \a key is already
+       * present, it will be replaced.
+       */
+      void setItem(const String &key, const Item &item);
+
+    protected:
+
+      /*!
+       * Reads from the file specified in the constructor.
+       */
+      void read();
+
+      /*!
+       * Parses the body of the tag in \a data.
+       */
+      void parse(const ByteVector &data);
+
+    private:
+      Tag(const Tag &);
+      Tag &operator=(const Tag &);
+
+      class TagPrivate;
+      TagPrivate *d;
+    };
+  }
+}
+
+#endif
diff --git a/src/taglib/asf/asfattribute.cpp b/src/taglib/asf/asfattribute.cpp
new file mode 100644 (file)
index 0000000..85db872
--- /dev/null
@@ -0,0 +1,342 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_ASF
+
+#include <taglib.h>
+#include <tdebug.h>
+#include "asfattribute.h"
+#include "asffile.h"
+
+using namespace TagLib;
+
+class ASF::Attribute::AttributePrivate : public RefCounter
+{
+public:
+  AttributePrivate()
+    : stream(0),
+      language(0) {}
+  AttributeTypes type;
+  String stringValue;
+  ByteVector byteVectorValue;
+  union {
+    unsigned int intValue;
+    unsigned short shortValue;
+    unsigned long long longLongValue;
+    bool boolValue;
+  };
+  int stream;
+  int language;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+ASF::Attribute::Attribute()
+{
+  d = new AttributePrivate;
+  d->type = UnicodeType;
+}
+
+ASF::Attribute::Attribute(const ASF::Attribute &other)
+  : d(other.d)
+{
+  d->ref();
+}
+
+ASF::Attribute &
+ASF::Attribute::operator=(const ASF::Attribute &other)
+{
+  if(d->deref())
+    delete d;
+  d = other.d;
+  d->ref();
+  return *this;
+}
+
+ASF::Attribute::~Attribute()
+{
+  if(d->deref())
+    delete d;
+}
+
+ASF::Attribute::Attribute(const String &value)
+{
+  d = new AttributePrivate;
+  d->type = UnicodeType;
+  d->stringValue = value;
+}
+
+ASF::Attribute::Attribute(const ByteVector &value)
+{
+  d = new AttributePrivate;
+  d->type = BytesType;
+  d->byteVectorValue = value;
+}
+
+ASF::Attribute::Attribute(unsigned int value)
+{
+  d = new AttributePrivate;
+  d->type = DWordType;
+  d->intValue = value;
+}
+
+ASF::Attribute::Attribute(unsigned long long value)
+{
+  d = new AttributePrivate;
+  d->type = QWordType;
+  d->longLongValue = value;
+}
+
+ASF::Attribute::Attribute(unsigned short value)
+{
+  d = new AttributePrivate;
+  d->type = WordType;
+  d->shortValue = value;
+}
+
+ASF::Attribute::Attribute(bool value)
+{
+  d = new AttributePrivate;
+  d->type = BoolType;
+  d->boolValue = value;
+}
+
+ASF::Attribute::AttributeTypes
+ASF::Attribute::type() const
+{
+  return d->type;
+}
+
+String
+ASF::Attribute::toString() const
+{
+  return d->stringValue;
+}
+
+ByteVector
+ASF::Attribute::toByteVector() const
+{
+  return d->byteVectorValue;
+}
+
+unsigned short
+ASF::Attribute::toBool() const
+{
+  return d->shortValue;
+}
+
+unsigned short
+ASF::Attribute::toUShort() const
+{
+  return d->shortValue;
+}
+
+unsigned int
+ASF::Attribute::toUInt() const
+{
+  return d->intValue;
+}
+
+unsigned long long
+ASF::Attribute::toULongLong() const
+{
+  return d->longLongValue;
+}
+
+String
+ASF::Attribute::parse(ASF::File &f, int kind)
+{
+  int size, nameLength;
+  String name;
+
+  // extended content descriptor
+  if(kind == 0) {
+    nameLength = f.readWORD();
+    name = f.readString(nameLength);
+    d->type = ASF::Attribute::AttributeTypes(f.readWORD());
+    size = f.readWORD();
+  }
+  // metadata & metadata library
+  else {
+    int temp = f.readWORD();
+    // metadata library
+    if(kind == 2) {
+      d->language = temp;
+    }
+    d->stream = f.readWORD();
+    nameLength = f.readWORD();
+    d->type = ASF::Attribute::AttributeTypes(f.readWORD());
+    size = f.readDWORD();
+    name = f.readString(nameLength);
+  }
+
+  if(kind != 2 && size > 65535) {
+    debug("ASF::Attribute::parse() -- Value larger than 64kB");
+  }
+
+  switch(d->type) {
+  case WordType:
+    d->shortValue = f.readWORD();
+    break;
+
+  case BoolType:
+    if(kind == 0) {
+      d->boolValue = f.readDWORD() == 1;
+    }
+    else {
+      d->boolValue = f.readWORD() == 1;
+    }
+    break;
+
+  case DWordType:
+    d->intValue = f.readDWORD();
+    break;
+
+  case QWordType:
+    d->longLongValue = f.readQWORD();
+    break;
+
+  case UnicodeType:
+    d->stringValue = f.readString(size);
+    break;
+
+  case BytesType:
+  case GuidType:
+    d->byteVectorValue = f.readBlock(size);
+    break;
+  }
+
+  return name;
+}
+
+int
+ASF::Attribute::dataSize() const
+{
+  switch (d->type) {
+  case WordType:
+    return 2;
+  case BoolType:
+    return 4;
+  case DWordType:
+    return 4;
+  case QWordType:
+    return 5;
+  case UnicodeType:
+    return d->stringValue.size() * 2 + 2;
+  case BytesType:
+  case GuidType:
+    return d->byteVectorValue.size();
+  }
+  return 0;
+}
+
+ByteVector
+ASF::Attribute::render(const String &name, int kind) const
+{
+  ByteVector data;
+
+  switch (d->type) {
+  case WordType:
+    data.append(ByteVector::fromShort(d->shortValue, false));
+    break;
+
+  case BoolType:
+    if(kind == 0) {
+      data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false));
+    }
+    else {
+      data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false));
+    }
+    break;
+
+  case DWordType:
+    data.append(ByteVector::fromUInt(d->intValue, false));
+    break;
+
+  case QWordType:
+    data.append(ByteVector::fromLongLong(d->longLongValue, false));
+    break;
+
+  case UnicodeType:
+    data.append(File::renderString(d->stringValue));
+    break;
+
+  case BytesType:
+  case GuidType:
+    data.append(d->byteVectorValue);
+    break;
+  }
+
+  if(kind == 0) {
+    data = File::renderString(name, true) +
+           ByteVector::fromShort((int)d->type, false) +
+           ByteVector::fromShort(data.size(), false) +
+           data;
+  }
+  else {
+    ByteVector nameData = File::renderString(name);
+    data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
+           ByteVector::fromShort(d->stream, false) +
+           ByteVector::fromShort(nameData.size(), false) +
+           ByteVector::fromShort((int)d->type, false) +
+           ByteVector::fromUInt(data.size(), false) +
+           nameData +
+           data;
+  }
+
+  return data;
+}
+
+int
+ASF::Attribute::language() const
+{
+  return d->language;
+}
+
+void
+ASF::Attribute::setLanguage(int value)
+{
+  d->language = value;
+}
+
+int
+ASF::Attribute::stream() const
+{
+  return d->stream;
+}
+
+void
+ASF::Attribute::setStream(int value)
+{
+  d->stream = value;
+}
+
+#endif
diff --git a/src/taglib/asf/asfattribute.h b/src/taglib/asf/asfattribute.h
new file mode 100644 (file)
index 0000000..9752389
--- /dev/null
@@ -0,0 +1,184 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_ASFATTRIBUTE_H
+#define TAGLIB_ASFATTRIBUTE_H
+
+#include "tstring.h"
+#include "tbytevector.h"
+#include "taglib_export.h"
+
+namespace TagLib
+{
+
+  namespace ASF
+  {
+
+    class File;
+
+    class TAGLIB_EXPORT Attribute
+    {
+    public:
+
+      /*!
+       * Enum of types an Attribute can have.
+       */
+      enum AttributeTypes {
+        UnicodeType = 0,
+        BytesType   = 1,
+        BoolType    = 2,
+        DWordType   = 3,
+        QWordType   = 4,
+        WordType    = 5,
+        GuidType    = 6
+      };
+
+      /*!
+       * Constructs an empty attribute.
+       */
+      Attribute();
+
+      /*!
+       * Constructs an attribute with \a key and a UnicodeType \a value.
+       */
+      Attribute(const String &value);
+
+      /*!
+       * Constructs an attribute with \a key and a BytesType \a value.
+       */
+      Attribute(const ByteVector &value);
+
+      /*!
+       * Constructs an attribute with \a key and a DWordType \a value.
+       */
+      Attribute(unsigned int value);
+
+      /*!
+       * Constructs an attribute with \a key and a QWordType \a value.
+       */
+      Attribute(unsigned long long value);
+
+      /*!
+       * Constructs an attribute with \a key and a WordType \a value.
+       */
+      Attribute(unsigned short value);
+
+      /*!
+       * Constructs an attribute with \a key and a BoolType \a value.
+       */
+      Attribute(bool value);
+
+      /*!
+       * Construct an attribute as a copy of \a other.
+       */
+      Attribute(const Attribute &item);
+
+      /*!
+       * Copies the contents of \a other into this item.
+       */
+      ASF::Attribute &operator=(const Attribute &other);
+
+      /*!
+       * Destroys the attribute.
+       */
+      virtual ~Attribute();
+
+      /*!
+       * Returns type of the value.
+       */
+      AttributeTypes type() const;
+
+      /*!
+       * Returns the BoolType \a value.
+       */
+      unsigned short toBool() const;
+
+      /*!
+       * Returns the WordType \a value.
+       */
+      unsigned short toUShort() const;
+
+      /*!
+       * Returns the DWordType \a value.
+       */
+      unsigned int toUInt() const;
+
+      /*!
+       * Returns the QWordType \a value.
+       */
+      unsigned long long toULongLong() const;
+
+      /*!
+       * Returns the UnicodeType \a value.
+       */
+      String toString() const;
+
+      /*!
+       * Returns the BytesType \a value.
+       */
+      ByteVector toByteVector() const;
+
+      /*!
+       * Returns the language number, or 0 is no stream number was set.
+       */
+      int language() const;
+
+      /*!
+       * Sets the language number.
+       */
+      void setLanguage(int value);
+
+      /*!
+       * Returns the stream number, or 0 is no stream number was set.
+       */
+      int stream() const;
+
+      /*!
+       * Sets the stream number.
+       */
+      void setStream(int value);
+
+#ifndef DO_NOT_DOCUMENT
+      /* THIS IS PRIVATE, DON'T TOUCH IT! */
+      String parse(ASF::File &file, int kind = 0);
+#endif
+
+      //! Returns the size of the stored data
+      int dataSize() const;
+
+    private:
+      friend class File;
+
+      ByteVector render(const String &name, int kind = 0) const;
+
+      class AttributePrivate;
+      AttributePrivate *d;
+    };
+
+  }
+
+}
+
+#endif
diff --git a/src/taglib/asf/asffile.cpp b/src/taglib/asf/asffile.cpp
new file mode 100644 (file)
index 0000000..012f39b
--- /dev/null
@@ -0,0 +1,563 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_ASF
+
+#include <tdebug.h>
+#include <tbytevectorlist.h>
+#include <tstring.h>
+#include "asffile.h"
+#include "asftag.h"
+#include "asfproperties.h"
+
+using namespace TagLib;
+
+class ASF::File::FilePrivate
+{
+public:
+  FilePrivate():
+    size(0),
+    tag(0),
+    properties(0),
+    contentDescriptionObject(0),
+    extendedContentDescriptionObject(0),
+    headerExtensionObject(0),
+    metadataObject(0),
+    metadataLibraryObject(0) {}
+  unsigned long long size;
+  ASF::Tag *tag;
+  ASF::Properties *properties;
+  List<ASF::File::BaseObject *> objects;
+  ASF::File::ContentDescriptionObject *contentDescriptionObject;
+  ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
+  ASF::File::HeaderExtensionObject *headerExtensionObject;
+  ASF::File::MetadataObject *metadataObject;
+  ASF::File::MetadataLibraryObject *metadataLibraryObject;
+};
+
+static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
+static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
+static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
+static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
+static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
+static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
+static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
+static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
+
+class ASF::File::BaseObject
+{
+public:
+  ByteVector data;
+  virtual ~BaseObject() {}
+  virtual ByteVector guid() = 0;
+  virtual void parse(ASF::File *file, unsigned int size);
+  virtual ByteVector render(ASF::File *file);
+};
+
+class ASF::File::UnknownObject : public ASF::File::BaseObject
+{
+  ByteVector myGuid;
+public:
+  UnknownObject(const ByteVector &guid);
+  ByteVector guid();
+};
+
+class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
+{
+public:
+  ByteVector guid();
+  void parse(ASF::File *file, uint size);
+};
+
+class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
+{
+public:
+  ByteVector guid();
+  void parse(ASF::File *file, uint size);
+};
+
+class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
+{
+public:
+  ByteVector guid();
+  void parse(ASF::File *file, uint size);
+  ByteVector render(ASF::File *file);
+};
+
+class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
+{
+public:
+  ByteVectorList attributeData;
+  ByteVector guid();
+  void parse(ASF::File *file, uint size);
+  ByteVector render(ASF::File *file);
+};
+
+class ASF::File::MetadataObject : public ASF::File::BaseObject
+{
+public:
+  ByteVectorList attributeData;
+  ByteVector guid();
+  void parse(ASF::File *file, uint size);
+  ByteVector render(ASF::File *file);
+};
+
+class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
+{
+public:
+  ByteVectorList attributeData;
+  ByteVector guid();
+  void parse(ASF::File *file, uint size);
+  ByteVector render(ASF::File *file);
+};
+
+class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
+{
+public:
+  List<ASF::File::BaseObject *> objects;
+  ByteVector guid();
+  void parse(ASF::File *file, uint size);
+  ByteVector render(ASF::File *file);
+};
+
+void
+ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
+{
+  data = file->readBlock(size - 24);
+}
+
+ByteVector
+ASF::File::BaseObject::render(ASF::File * /*file*/)
+{
+  return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
+}
+
+ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
+{
+}
+
+ByteVector
+ASF::File::UnknownObject::guid()
+{
+  return myGuid;
+}
+
+ByteVector
+ASF::File::FilePropertiesObject::guid()
+{
+  return filePropertiesGuid;
+}
+
+void
+ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
+{
+  BaseObject::parse(file, size);
+  file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
+}
+
+ByteVector
+ASF::File::StreamPropertiesObject::guid()
+{
+  return streamPropertiesGuid;
+}
+
+void
+ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
+{
+  BaseObject::parse(file, size);
+  file->d->properties->setChannels(data.mid(56, 2).toShort(false));
+  file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
+  file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
+}
+
+ByteVector
+ASF::File::ContentDescriptionObject::guid()
+{
+  return contentDescriptionGuid;
+}
+
+void
+ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
+{
+  file->d->contentDescriptionObject = this;
+  int titleLength = file->readWORD();
+  int artistLength = file->readWORD();
+  int copyrightLength = file->readWORD();
+  int commentLength = file->readWORD();
+  int ratingLength = file->readWORD();
+  file->d->tag->setTitle(file->readString(titleLength));
+  file->d->tag->setArtist(file->readString(artistLength));
+  file->d->tag->setCopyright(file->readString(copyrightLength));
+  file->d->tag->setComment(file->readString(commentLength));
+  file->d->tag->setRating(file->readString(ratingLength));
+}
+
+ByteVector
+ASF::File::ContentDescriptionObject::render(ASF::File *file)
+{
+  ByteVector v1 = file->renderString(file->d->tag->title());
+  ByteVector v2 = file->renderString(file->d->tag->artist());
+  ByteVector v3 = file->renderString(file->d->tag->copyright());
+  ByteVector v4 = file->renderString(file->d->tag->comment());
+  ByteVector v5 = file->renderString(file->d->tag->rating());
+  data.clear();
+  data.append(ByteVector::fromShort(v1.size(), false));
+  data.append(ByteVector::fromShort(v2.size(), false));
+  data.append(ByteVector::fromShort(v3.size(), false));
+  data.append(ByteVector::fromShort(v4.size(), false));
+  data.append(ByteVector::fromShort(v5.size(), false));
+  data.append(v1);
+  data.append(v2);
+  data.append(v3);
+  data.append(v4);
+  data.append(v5);
+  return BaseObject::render(file);
+}
+
+ByteVector
+ASF::File::ExtendedContentDescriptionObject::guid()
+{
+  return extendedContentDescriptionGuid;
+}
+
+void
+ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
+{
+  file->d->extendedContentDescriptionObject = this;
+  int count = file->readWORD();
+  while(count--) {
+    ASF::Attribute attribute;
+    String name = attribute.parse(*file);
+    file->d->tag->addAttribute(name, attribute);
+  }
+}
+
+ByteVector
+ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
+{
+  data.clear();
+  data.append(ByteVector::fromShort(attributeData.size(), false));
+  data.append(attributeData.toByteVector(ByteVector::null));
+  return BaseObject::render(file);
+}
+
+ByteVector
+ASF::File::MetadataObject::guid()
+{
+  return metadataGuid;
+}
+
+void
+ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
+{
+  file->d->metadataObject = this;
+  int count = file->readWORD();
+  while(count--) {
+    ASF::Attribute attribute;
+    String name = attribute.parse(*file, 1);
+    file->d->tag->addAttribute(name, attribute);
+  }
+}
+
+ByteVector
+ASF::File::MetadataObject::render(ASF::File *file)
+{
+  data.clear();
+  data.append(ByteVector::fromShort(attributeData.size(), false));
+  data.append(attributeData.toByteVector(ByteVector::null));
+  return BaseObject::render(file);
+}
+
+ByteVector
+ASF::File::MetadataLibraryObject::guid()
+{
+  return metadataLibraryGuid;
+}
+
+void
+ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
+{
+  file->d->metadataLibraryObject = this;
+  int count = file->readWORD();
+  while(count--) {
+    ASF::Attribute attribute;
+    String name = attribute.parse(*file, 2);
+    file->d->tag->addAttribute(name, attribute);
+  }
+}
+
+ByteVector
+ASF::File::MetadataLibraryObject::render(ASF::File *file)
+{
+  data.clear();
+  data.append(ByteVector::fromShort(attributeData.size(), false));
+  data.append(attributeData.toByteVector(ByteVector::null));
+  return BaseObject::render(file);
+}
+
+ByteVector
+ASF::File::HeaderExtensionObject::guid()
+{
+  return headerExtensionGuid;
+}
+
+void
+ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
+{
+  file->d->headerExtensionObject = this;
+  file->seek(18, File::Current);
+  long long dataSize = file->readDWORD();
+  long long dataPos = 0;
+  while(dataPos < dataSize) {
+    ByteVector guid = file->readBlock(16);
+    long long size = file->readQWORD();
+    BaseObject *obj;
+    if(guid == metadataGuid) {
+      obj = new MetadataObject();
+    }
+    else if(guid == metadataLibraryGuid) {
+      obj = new MetadataLibraryObject();
+    }
+    else {
+      obj = new UnknownObject(guid);
+    }
+    obj->parse(file, size);
+    objects.append(obj);
+    dataPos += size;
+  }
+}
+
+ByteVector
+ASF::File::HeaderExtensionObject::render(ASF::File *file)
+{
+  data.clear();
+  for(unsigned int i = 0; i < objects.size(); i++) {
+    data.append(objects[i]->render(file));
+  }
+  data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
+  return BaseObject::render(file);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) 
+  : TagLib::File(file)
+{
+  d = new FilePrivate;
+  read(readProperties, propertiesStyle);
+}
+
+ASF::File::~File()
+{
+  for(unsigned int i = 0; i < d->objects.size(); i++) {
+    delete d->objects[i];
+  }
+  if(d->tag) {
+    delete d->tag;
+  }
+  if(d->properties) {
+    delete d->properties;
+  }
+  delete d;
+}
+
+ASF::Tag *ASF::File::tag() const
+{
+  return d->tag;
+}
+
+ASF::Properties *ASF::File::audioProperties() const
+{
+  return d->properties;
+}
+
+void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
+{
+  if(!isValid())
+    return;
+
+  ByteVector guid = readBlock(16);
+  if(guid != headerGuid) {
+    debug("ASF: Not an ASF file.");
+    return;
+  }
+
+  d->tag = new ASF::Tag();
+  d->properties = new ASF::Properties();
+
+  d->size = readQWORD();
+  int numObjects = readDWORD();
+  seek(2, Current);
+
+  for(int i = 0; i < numObjects; i++) {
+    ByteVector guid = readBlock(16);
+    long size = (long)readQWORD();
+    BaseObject *obj;
+    if(guid == filePropertiesGuid) {
+      obj = new FilePropertiesObject();
+    }
+    else if(guid == streamPropertiesGuid) {
+      obj = new StreamPropertiesObject();
+    }
+    else if(guid == contentDescriptionGuid) {
+      obj = new ContentDescriptionObject();
+    }
+    else if(guid == extendedContentDescriptionGuid) {
+      obj = new ExtendedContentDescriptionObject();
+    }
+    else if(guid == headerExtensionGuid) {
+      obj = new HeaderExtensionObject();
+    }
+    else {
+      obj = new UnknownObject(guid);
+    }
+    obj->parse(this, size);
+    d->objects.append(obj);
+  }
+}
+
+bool ASF::File::save()
+{
+  if(readOnly()) {
+    debug("ASF: File is read-only.");
+    return false;
+  }
+
+  if(!d->contentDescriptionObject) {
+    d->contentDescriptionObject = new ContentDescriptionObject();
+    d->objects.append(d->contentDescriptionObject);
+  }
+  if(!d->extendedContentDescriptionObject) {
+    d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
+    d->objects.append(d->extendedContentDescriptionObject);
+  }
+  if(!d->headerExtensionObject) {
+    d->headerExtensionObject = new HeaderExtensionObject();
+    d->objects.append(d->headerExtensionObject);
+  }
+  if(!d->metadataObject) {
+    d->metadataObject = new MetadataObject();
+    d->headerExtensionObject->objects.append(d->metadataObject);
+  }
+  if(!d->metadataLibraryObject) {
+    d->metadataLibraryObject = new MetadataLibraryObject();
+    d->headerExtensionObject->objects.append(d->metadataLibraryObject);
+  }
+
+  ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
+  for(; it != d->tag->attributeListMap().end(); it++) {
+    const String &name = it->first;
+    const AttributeList &attributes = it->second;
+    bool inExtendedContentDescriptionObject = false;
+    bool inMetadataObject = false;
+    for(unsigned int j = 0; j < attributes.size(); j++) {
+      const Attribute &attribute = attributes[j];
+      bool largeValue = attribute.dataSize() > 65535;
+      if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
+        d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
+        inExtendedContentDescriptionObject = true;
+      }
+      else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
+        d->metadataObject->attributeData.append(attribute.render(name, 1));
+        inMetadataObject = true;
+      }
+      else {
+        d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
+      }
+    }
+  }
+
+  ByteVector data;
+  for(unsigned int i = 0; i < d->objects.size(); i++) {
+    data.append(d->objects[i]->render(this));
+  }
+  data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
+  insert(data, 0, d->size);
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected members
+////////////////////////////////////////////////////////////////////////////////
+
+int ASF::File::readBYTE()
+{
+  ByteVector v = readBlock(1);
+  return v[0];
+}
+
+int ASF::File::readWORD()
+{
+  ByteVector v = readBlock(2);
+  return v.toShort(false);
+}
+
+unsigned int ASF::File::readDWORD()
+{
+  ByteVector v = readBlock(4);
+  return v.toUInt(false);
+}
+
+long long ASF::File::readQWORD()
+{
+  ByteVector v = readBlock(8);
+  return v.toLongLong(false);
+}
+
+String
+ASF::File::readString(int length)
+{
+  ByteVector data = readBlock(length);
+  unsigned int size = data.size();
+  while (size >= 2) {
+    if(data[size - 1] != '\0' || data[size - 2] != '\0') {
+      break;
+    }
+    size -= 2;
+  }
+  if(size != data.size()) {
+    data.resize(size);
+  }
+  return String(data, String::UTF16LE);
+}
+
+ByteVector
+ASF::File::renderString(const String &str, bool includeLength)
+{
+  ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
+  if(includeLength) {
+    data = ByteVector::fromShort(data.size(), false) + data;
+  }
+  return data;
+}
+
+#endif
diff --git a/src/taglib/asf/asffile.h b/src/taglib/asf/asffile.h
new file mode 100644 (file)
index 0000000..23a6d00
--- /dev/null
@@ -0,0 +1,119 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_ASFFILE_H
+#define TAGLIB_ASFFILE_H
+
+#include "tag.h"
+#include "tfile.h"
+#include "taglib_export.h"
+#include "asfproperties.h"
+#include "asftag.h"
+
+namespace TagLib {
+
+  //! An implementation of ASF (WMA) metadata
+  namespace ASF {
+
+    /*!
+     * This implements and provides an interface for ASF files to the
+     * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
+     * the abstract TagLib::File API as well as providing some additional
+     * information specific to ASF files.
+     */
+    class TAGLIB_EXPORT File : public TagLib::File
+    {
+    public:
+
+      /*!
+       * Contructs an ASF file from \a file.  If \a readProperties is true the
+       * file's audio properties will also be read using \a propertiesStyle.  If
+       * false, \a propertiesStyle is ignored.
+       *
+       * \note In the current implementation, both \a readProperties and
+       * \a propertiesStyle are ignored.
+       */
+      File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
+
+      /*!
+       * Destroys this instance of the File.
+       */
+      virtual ~File();
+
+      /*!
+       * Returns a pointer to the ASF tag of the file.
+       *
+       * ASF::Tag implements the tag interface, so this serves as the
+       * reimplementation of TagLib::File::tag().
+       *
+       * \note The Tag <b>is still</b> owned by the ASF::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      virtual Tag *tag() const;
+
+      /*!
+       * Returns the ASF audio properties for this file.
+       */
+      virtual Properties *audioProperties() const;
+
+      /*!
+       * Save the file.
+       *
+       * This returns true if the save was successful.
+       */
+      virtual bool save();
+
+    private:
+
+      int readBYTE();
+      int readWORD();
+      unsigned int readDWORD();
+      long long readQWORD();
+      static ByteVector renderString(const String &str, bool includeLength = false);
+      String readString(int len);
+      void read(bool readProperties, Properties::ReadStyle propertiesStyle);
+
+      friend class Attribute;
+
+      class BaseObject;
+      class UnknownObject;
+      class FilePropertiesObject;
+      class StreamPropertiesObject;
+      class ContentDescriptionObject;
+      class ExtendedContentDescriptionObject;
+      class HeaderExtensionObject;
+      class MetadataObject;
+      class MetadataLibraryObject;
+
+      class FilePrivate;
+      FilePrivate *d;
+    };
+
+  }
+
+}
+
+#endif
diff --git a/src/taglib/asf/asfproperties.cpp b/src/taglib/asf/asfproperties.cpp
new file mode 100644 (file)
index 0000000..68e2d4c
--- /dev/null
@@ -0,0 +1,107 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_ASF
+
+#include <tdebug.h>
+#include <tstring.h>
+#include "asfproperties.h"
+
+using namespace TagLib;
+
+class ASF::Properties::PropertiesPrivate
+{
+public:
+  PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0) {}
+  int length;
+  int bitrate;
+  int sampleRate;
+  int channels;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+ASF::Properties::Properties() : AudioProperties(AudioProperties::Average)
+{
+  d = new PropertiesPrivate;
+}
+
+ASF::Properties::~Properties()
+{
+  if(d)
+    delete d;  
+}
+
+int ASF::Properties::length() const
+{
+  return d->length;
+}
+
+int ASF::Properties::bitrate() const
+{
+  return d->bitrate;
+}
+
+int ASF::Properties::sampleRate() const
+{
+  return d->sampleRate;
+}
+
+int ASF::Properties::channels() const
+{
+  return d->channels;
+} 
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+void ASF::Properties::setLength(int length)
+{
+  d->length = length;
+}
+
+void ASF::Properties::setBitrate(int length)
+{
+  d->bitrate = length;
+}
+
+void ASF::Properties::setSampleRate(int length)
+{
+  d->sampleRate = length;
+}
+
+void ASF::Properties::setChannels(int length)
+{
+  d->channels = length;
+}
+
+#endif
diff --git a/src/taglib/asf/asfproperties.h b/src/taglib/asf/asfproperties.h
new file mode 100644 (file)
index 0000000..653b015
--- /dev/null
@@ -0,0 +1,74 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_ASFPROPERTIES_H
+#define TAGLIB_ASFPROPERTIES_H
+
+#include "audioproperties.h"
+#include "tstring.h"
+#include "taglib_export.h"
+
+namespace TagLib {
+
+  namespace ASF {
+
+    //! An implementation of ASF audio properties
+    class TAGLIB_EXPORT Properties : public AudioProperties
+    {
+    public:
+
+      /*!
+       * Create an instance of ASF::Properties.
+       */
+      Properties();
+
+      /*!
+       * Destroys this ASF::Properties instance.
+       */
+      virtual ~Properties();
+
+      // Reimplementations.
+      virtual int length() const;
+      virtual int bitrate() const;
+      virtual int sampleRate() const;
+      virtual int channels() const;
+
+#ifndef DO_NOT_DOCUMENT
+      void setLength(int value);
+      void setBitrate(int value);
+      void setSampleRate(int value);
+      void setChannels(int value);
+#endif
+
+    private:
+      class PropertiesPrivate;
+      PropertiesPrivate *d;
+    };
+
+  }
+
+}
+
+#endif 
diff --git a/src/taglib/asf/asftag.cpp b/src/taglib/asf/asftag.cpp
new file mode 100644 (file)
index 0000000..f910ccb
--- /dev/null
@@ -0,0 +1,219 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_ASF
+
+#include "asftag.h"
+
+using namespace TagLib;
+
+class ASF::Tag::TagPrivate
+{
+public:
+  String title;
+  String artist;
+  String copyright;
+  String comment;
+  String rating;
+  AttributeListMap attributeListMap;
+};
+
+ASF::Tag::Tag()
+: TagLib::Tag()
+{
+  d = new TagPrivate;
+}
+
+ASF::Tag::~Tag()
+{
+  if(d)
+    delete d;
+}
+
+String
+ASF::Tag::title() const
+{
+  return d->title;
+}
+
+String
+ASF::Tag::artist() const
+{
+  return d->artist;
+}
+
+String
+ASF::Tag::album() const
+{
+  if(d->attributeListMap.contains("WM/AlbumTitle"))
+    return d->attributeListMap["WM/AlbumTitle"][0].toString();
+  return String::null;
+}
+
+String
+ASF::Tag::copyright() const
+{
+  return d->copyright;
+}
+
+String
+ASF::Tag::comment() const
+{
+  return d->comment;
+}
+
+String
+ASF::Tag::rating() const
+{
+  return d->rating;
+}
+
+unsigned int
+ASF::Tag::year() const
+{
+  if(d->attributeListMap.contains("WM/Year"))
+    return d->attributeListMap["WM/Year"][0].toString().toInt();
+  return 0;
+}
+
+unsigned int
+ASF::Tag::track() const
+{
+  if(d->attributeListMap.contains("WM/TrackNumber")) {
+    const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
+    if(attr.type() == ASF::Attribute::DWordType)
+      return attr.toUInt();
+    else
+      return attr.toString().toInt();
+  }
+  if(d->attributeListMap.contains("WM/Track"))
+    return d->attributeListMap["WM/Track"][0].toUInt();
+  return 0;
+}
+
+String
+ASF::Tag::genre() const
+{
+  if(d->attributeListMap.contains("WM/Genre"))
+    return d->attributeListMap["WM/Genre"][0].toString();
+  return String::null;
+}
+
+void
+ASF::Tag::setTitle(const String &value)
+{
+  d->title = value;
+}
+
+void
+ASF::Tag::setArtist(const String &value)
+{
+  d->artist = value;
+}
+
+void
+ASF::Tag::setCopyright(const String &value)
+{
+  d->copyright = value;
+}
+
+void
+ASF::Tag::setComment(const String &value)
+{
+  d->comment = value;
+}
+
+void
+ASF::Tag::setRating(const String &value)
+{
+  d->rating = value;
+}
+
+void
+ASF::Tag::setAlbum(const String &value)
+{
+  setAttribute("WM/AlbumTitle", value);
+}
+
+void
+ASF::Tag::setGenre(const String &value)
+{
+  setAttribute("WM/Genre", value);
+}
+
+void
+ASF::Tag::setYear(uint value)
+{
+  setAttribute("WM/Year", String::number(value));
+}
+
+void
+ASF::Tag::setTrack(uint value)
+{
+  setAttribute("WM/TrackNumber", String::number(value));
+}
+
+ASF::AttributeListMap&
+ASF::Tag::attributeListMap()
+{
+  return d->attributeListMap;
+}
+
+void ASF::Tag::removeItem(const String &key)
+{
+  AttributeListMap::Iterator it = d->attributeListMap.find(key);
+  if(it != d->attributeListMap.end())
+    d->attributeListMap.erase(it);
+}
+
+void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
+{
+  AttributeList value;
+  value.append(attribute);
+  d->attributeListMap.insert(name, value);
+}
+
+void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
+{
+  if(d->attributeListMap.contains(name)) {
+    d->attributeListMap[name].append(attribute);
+  }
+  else {
+    setAttribute(name, attribute);
+  }
+}
+
+bool ASF::Tag::isEmpty() const {
+  return TagLib::Tag::isEmpty() &&
+         copyright().isEmpty() &&
+         rating().isEmpty() &&
+         d->attributeListMap.isEmpty();
+}
+
+#endif
diff --git a/src/taglib/asf/asftag.h b/src/taglib/asf/asftag.h
new file mode 100644 (file)
index 0000000..8e73067
--- /dev/null
@@ -0,0 +1,186 @@
+/**************************************************************************
+    copyright            : (C) 2005-2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_ASFTAG_H
+#define TAGLIB_ASFTAG_H
+
+#include "tag.h"
+#include "tlist.h"
+#include "tmap.h"
+#include "taglib_export.h"
+#include "asfattribute.h"
+
+namespace TagLib {
+
+  namespace ASF {
+
+    typedef List<Attribute> AttributeList;
+    typedef Map<String, AttributeList> AttributeListMap;
+
+    class TAGLIB_EXPORT Tag : public TagLib::Tag {
+
+      friend class File;
+
+    public:
+
+      Tag();
+
+      virtual ~Tag();
+
+      /*!
+       * Returns the track name.
+       */
+      virtual String title() const;
+
+      /*!
+       * Returns the artist name.
+       */
+      virtual String artist() const;
+
+      /*!
+       * Returns the album name; if no album name is present in the tag
+       * String::null will be returned.
+       */
+      virtual String album() const;
+
+      /*!
+       * Returns the track comment.
+       */
+      virtual String comment() const;
+
+      /*!
+       * Returns the genre name; if no genre is present in the tag String::null
+       * will be returned.
+       */
+      virtual String genre() const;
+
+      /*!
+       * Returns the rating.
+       */
+      virtual String rating() const;
+
+      /*!
+       * Returns the genre name; if no genre is present in the tag String::null
+       * will be returned.
+       */
+      virtual String copyright() const;
+
+      /*!
+       * Returns the year; if there is no year set, this will return 0.
+       */
+      virtual uint year() const;
+
+      /*!
+       * Returns the track number; if there is no track number set, this will
+       * return 0.
+       */
+      virtual uint track() const;
+
+      /*!
+       * Sets the title to \a s.
+       */
+      virtual void setTitle(const String &s);
+
+      /*!
+       * Sets the artist to \a s.
+       */
+      virtual void setArtist(const String &s);
+
+      /*!
+       * Sets the album to \a s.  If \a s is String::null then this value will be
+       * cleared.
+       */
+      virtual void setAlbum(const String &s);
+
+      /*!
+       * Sets the comment to \a s.
+       */
+      virtual void setComment(const String &s);
+
+      /*!
+       * Sets the rating to \a s. 
+       */
+      virtual void setRating(const String &s);
+
+      /*!
+       * Sets the copyright to \a s. 
+       */
+      virtual void setCopyright(const String &s);
+
+      /*!
+       * Sets the genre to \a s. 
+       */
+      virtual void setGenre(const String &s);
+
+      /*!
+       * Sets the year to \a i.  If \a s is 0 then this value will be cleared.
+       */
+      virtual void setYear(uint i);
+
+      /*!
+       * Sets the track to \a i.  If \a s is 0 then this value will be cleared.
+       */
+      virtual void setTrack(uint i);
+
+      /*!
+       * Returns true if the tag does not contain any data.  This should be
+       * reimplemented in subclasses that provide more than the basic tagging
+       * abilities in this class.
+       */
+      virtual bool isEmpty() const;
+
+      /*!
+       * Returns a reference to the item list map.  This is an AttributeListMap of
+       * all of the items in the tag.
+       *
+       * This is the most powerfull structure for accessing the items of the tag.
+       */
+      AttributeListMap &attributeListMap();
+
+      /*!
+       * Removes the \a key attribute from the tag
+       */
+      void removeItem(const String &name);
+
+      /*!
+       * Sets the \a key attribute to the value of \a attribute. If an attribute
+       * with the \a key is already present, it will be replaced.
+       */
+      void setAttribute(const String &name, const Attribute &attribute);
+
+      /*!
+       * Sets the \a key attribute to the value of \a attribute. If an attribute
+       * with the \a key is already present, it will be added to the list.
+       */
+      void addAttribute(const String &name, const Attribute &attribute);
+
+    private:
+
+      class TagPrivate;
+      TagPrivate *d;
+    };
+  }
+}
+#endif
diff --git a/src/taglib/audioproperties.cpp b/src/taglib/audioproperties.cpp
new file mode 100644 (file)
index 0000000..324cc35
--- /dev/null
@@ -0,0 +1,51 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include "audioproperties.h"
+
+using namespace TagLib;
+
+class AudioProperties::AudioPropertiesPrivate
+{
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public methods
+////////////////////////////////////////////////////////////////////////////////
+
+AudioProperties::~AudioProperties()
+{
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected methods
+////////////////////////////////////////////////////////////////////////////////
+
+AudioProperties::AudioProperties(ReadStyle)
+{
+
+}
diff --git a/src/taglib/audioproperties.h b/src/taglib/audioproperties.h
new file mode 100644 (file)
index 0000000..4841031
--- /dev/null
@@ -0,0 +1,110 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_AUDIOPROPERTIES_H
+#define TAGLIB_AUDIOPROPERTIES_H
+
+#include "taglib_export.h"
+
+namespace TagLib {
+
+  //! A simple, abstract interface to common audio properties
+
+  /*!
+   * The values here are common to most audio formats.  For more specific, codec
+   * dependant values, please see see the subclasses APIs.  This is meant to
+   * compliment the TagLib::File and TagLib::Tag APIs in providing a simple
+   * interface that is sufficient for most applications.
+   */
+
+  class TAGLIB_EXPORT AudioProperties
+  {
+  public:
+
+    /*!
+     * Reading audio properties from a file can sometimes be very time consuming
+     * and for the most accurate results can often involve reading the entire
+     * file.  Because in many situations speed is critical or the accuracy of the
+     * values is not particularly important this allows the level of desired
+     * accuracy to be set.
+     */
+    enum ReadStyle {
+      //! Read as little of the file as possible
+      Fast,
+      //! Read more of the file and make better values guesses
+      Average,
+      //! Read as much of the file as needed to report accurate values
+      Accurate
+    };
+
+    /*!
+     * Destroys this AudioProperties instance.
+     */
+    virtual ~AudioProperties();
+
+    /*!
+     * Returns the length of the file in seconds.
+     */
+    virtual int length() const = 0;
+
+    /*!
+     * Returns the most appropriate bit rate for the file in kb/s.  For constant
+     * bitrate formats this is simply the bitrate of the file.  For variable
+     * bitrate formats this is either the average or nominal bitrate.
+     */
+    virtual int bitrate() const = 0;
+
+    /*!
+     * Returns the sample rate in Hz.
+     */
+    virtual int sampleRate() const = 0;
+
+    /*!
+     * Returns the number of audio channels.
+     */
+    virtual int channels() const = 0;
+
+  protected:
+
+    /*!
+     * Construct an audio properties instance.  This is protected as this class
+     * should not be instantiated directly, but should be instantiated via its
+     * subclasses and can be fetched from the FileRef or File APIs.
+     *
+     * \see ReadStyle
+     */
+    AudioProperties(ReadStyle style);
+
+  private:
+    AudioProperties(const AudioProperties &);
+    AudioProperties &operator=(const AudioProperties &);
+
+    class AudioPropertiesPrivate;
+    AudioPropertiesPrivate *d;
+  };
+
+}
+
+#endif
diff --git a/src/taglib/fileref.cpp b/src/taglib/fileref.cpp
new file mode 100644 (file)
index 0000000..fec4516
--- /dev/null
@@ -0,0 +1,260 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tfile.h>
+#include <tstring.h>
+#include <tdebug.h>
+
+#include "fileref.h"
+#include "asffile.h"
+#include "mpegfile.h"
+#include "vorbisfile.h"
+#include "flacfile.h"
+#include "oggflacfile.h"
+#include "mpcfile.h"
+#include "mp4file.h"
+#include "wavpackfile.h"
+#include "speexfile.h"
+#include "trueaudiofile.h"
+#include "aifffile.h"
+#include "wavfile.h"
+
+using namespace TagLib;
+
+class FileRef::FileRefPrivate : public RefCounter
+{
+public:
+  FileRefPrivate(File *f) : RefCounter(), file(f) {}
+  ~FileRefPrivate() {
+    delete file;
+  }
+
+  File *file;
+  static List<const FileTypeResolver *> fileTypeResolvers;
+};
+
+List<const FileRef::FileTypeResolver *> FileRef::FileRefPrivate::fileTypeResolvers;
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+FileRef::FileRef()
+{
+  d = new FileRefPrivate(0);
+}
+
+FileRef::FileRef(FileName fileName, bool readAudioProperties,
+                 AudioProperties::ReadStyle audioPropertiesStyle)
+{
+  d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle));
+}
+
+FileRef::FileRef(File *file)
+{
+  d = new FileRefPrivate(file);
+}
+
+FileRef::FileRef(const FileRef &ref) : d(ref.d)
+{
+  d->ref();
+}
+
+FileRef::~FileRef()
+{
+  if(d->deref())
+    delete d;
+}
+
+Tag *FileRef::tag() const
+{
+  if(isNull()) {
+    debug("FileRef::tag() - Called without a valid file.");
+    return 0;
+  }
+  return d->file->tag();
+}
+
+AudioProperties *FileRef::audioProperties() const
+{
+  if(isNull()) {
+    debug("FileRef::audioProperties() - Called without a valid file.");
+    return 0;
+  }
+  return d->file->audioProperties();
+}
+
+File *FileRef::file() const
+{
+  return d->file;
+}
+
+bool FileRef::save()
+{
+  if(isNull()) {
+    debug("FileRef::save() - Called without a valid file.");
+    return false;
+  }
+  return d->file->save();
+}
+
+const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static
+{
+  FileRefPrivate::fileTypeResolvers.prepend(resolver);
+  return resolver;
+}
+
+StringList FileRef::defaultFileExtensions()
+{
+  StringList l;
+
+  l.append("ogg");
+  l.append("flac");
+  l.append("oga");
+  l.append("mp3");
+  l.append("mpc");
+  l.append("wv");
+  l.append("spx");
+  l.append("tta");
+#ifdef TAGLIB_WITH_MP4
+  l.append("m4a");
+  l.append("m4b");
+  l.append("m4p");
+  l.append("3g2");
+  l.append("mp4");
+#endif
+#ifdef TAGLIB_WITH_ASF
+  l.append("wma");
+  l.append("asf");
+#endif
+  l.append("aif");
+  l.append("aiff");
+  l.append("wav");
+
+  return l;
+}
+
+bool FileRef::isNull() const
+{
+  return !d->file || !d->file->isValid();
+}
+
+FileRef &FileRef::operator=(const FileRef &ref)
+{
+  if(&ref == this)
+    return *this;
+
+  if(d->deref())
+    delete d;
+
+  d = ref.d;
+  d->ref();
+
+  return *this;
+}
+
+bool FileRef::operator==(const FileRef &ref) const
+{
+  return ref.d->file == d->file;
+}
+
+bool FileRef::operator!=(const FileRef &ref) const
+{
+  return ref.d->file != d->file;
+}
+
+File *FileRef::create(FileName fileName, bool readAudioProperties,
+                      AudioProperties::ReadStyle audioPropertiesStyle) // static
+{
+
+  List<const FileTypeResolver *>::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin();
+
+  for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) {
+    File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
+    if(file)
+      return file;
+  }
+
+  // Ok, this is really dumb for now, but it works for testing.
+
+  String s;
+
+#ifdef _WIN32
+  s = (wcslen((const wchar_t *) fileName) > 0) ? String((const wchar_t *) fileName) : String((const char *) fileName);
+#else
+  s = fileName;
+#endif
+
+  // If this list is updated, the method defaultFileExtensions() should also be
+  // updated.  However at some point that list should be created at the same time
+  // that a default file type resolver is created.
+
+  int pos = s.rfind(".");
+  if(pos != -1) {
+    String ext = s.substr(pos + 1).upper();
+    if(ext == "MP3")
+      return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "OGG")
+      return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "OGA") {
+      /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
+      File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
+      if (file->isValid())
+        return file;
+      delete file;
+      return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
+    }
+    if(ext == "FLAC")
+      return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "MPC")
+      return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "WV")
+      return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "SPX")
+      return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "TTA")
+      return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
+#ifdef TAGLIB_WITH_MP4
+    if(ext == "M4A" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2")
+      return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
+#endif
+#ifdef TAGLIB_WITH_ASF
+    if(ext == "WMA" || ext == "ASF")
+      return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
+#endif
+    if(ext == "AIF")
+      return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "WAV")
+      return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "AIFF")
+      return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
+  }
+
+  return 0;
+}
diff --git a/src/taglib/fileref.h b/src/taglib/fileref.h
new file mode 100644 (file)
index 0000000..0cfe611
--- /dev/null
@@ -0,0 +1,260 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_FILEREF_H
+#define TAGLIB_FILEREF_H
+
+#include "tfile.h"
+#include "tstringlist.h"
+
+#include "taglib_export.h"
+#include "audioproperties.h"
+
+namespace TagLib {
+
+  class Tag;
+
+  //! This class provides a simple abstraction for creating and handling files
+
+  /*!
+   * FileRef exists to provide a minimal, generic and value-based wrapper around
+   * a File.  It is lightweight and implicitly shared, and as such suitable for
+   * pass-by-value use.  This hides some of the uglier details of TagLib::File
+   * and the non-generic portions of the concrete file implementations.
+   *
+   * This class is useful in a "simple usage" situation where it is desirable
+   * to be able to get and set some of the tag information that is similar
+   * across file types.
+   *
+   * Also note that it is probably a good idea to plug this into your mime
+   * type system rather than using the constructor that accepts a file name using
+   * the FileTypeResolver.
+   *
+   * \see FileTypeResolver
+   * \see addFileTypeResolver()
+   */
+
+  class TAGLIB_EXPORT FileRef
+  {
+  public:
+
+  //! A class for pluggable file type resolution.
+
+  /*!
+   * This class is used to add extend TagLib's very basic file name based file
+   * type resolution.
+   *
+   * This can be accomplished with:
+   *
+   * \code
+   *
+   * class MyFileTypeResolver : FileTypeResolver
+   * {
+   *   TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle)
+   *   {
+   *     if(someCheckForAnMP3File(fileName))
+   *       return new TagLib::MPEG::File(fileName);
+   *     return 0;
+   *   }
+   * }
+   *
+   * FileRef::addFileTypeResolver(new MyFileTypeResolver);
+   *
+   * \endcode
+   *
+   * Naturally a less contrived example would be slightly more complex.  This
+   * can be used to plug in mime-type detection systems or to add new file types
+   * to TagLib.
+   */
+
+    class TAGLIB_EXPORT FileTypeResolver
+    {
+      TAGLIB_IGNORE_MISSING_DESTRUCTOR
+    public:
+      /*!
+       * This method must be overridden to provide an additional file type
+       * resolver.  If the resolver is able to determine the file type it should
+       * return a valid File object; if not it should return 0.
+       *
+       * \note The created file is then owned by the FileRef and should not be
+       * deleted.  Deletion will happen automatically when the FileRef passes
+       * out of scope.
+       */
+      virtual File *createFile(FileName fileName,
+                               bool readAudioProperties = true,
+                               AudioProperties::ReadStyle
+                               audioPropertiesStyle = AudioProperties::Average) const = 0;
+    };
+
+    /*!
+     * Creates a null FileRef.
+     */
+    FileRef();
+
+    /*!
+     * Create a FileRef from \a fileName.  If \a readAudioProperties is true then
+     * the audio properties will be read using \a audioPropertiesStyle.  If
+     * \a readAudioProperties is false then \a audioPropertiesStyle will be
+     * ignored.
+     *
+     * Also see the note in the class documentation about why you may not want to
+     * use this method in your application.
+     */
+    explicit FileRef(FileName fileName,
+                     bool readAudioProperties = true,
+                     AudioProperties::ReadStyle
+                     audioPropertiesStyle = AudioProperties::Average);
+
+    /*!
+     * Contruct a FileRef using \a file.  The FileRef now takes ownership of the
+     * pointer and will delete the File when it passes out of scope.
+     */
+    explicit FileRef(File *file);
+
+    /*!
+     * Make a copy of \a ref.
+     */
+    FileRef(const FileRef &ref);
+
+    /*!
+     * Destroys this FileRef instance.
+     */
+    virtual ~FileRef();
+
+    /*!
+     * Returns a pointer to represented file's tag.
+     *
+     * \warning This pointer will become invalid when this FileRef and all
+     * copies pass out of scope.
+     *
+     * \see File::tag()
+     */
+    Tag *tag() const;
+
+    /*!
+     * Returns the audio properties for this FileRef.  If no audio properties
+     * were read then this will returns a null pointer.
+     */
+    AudioProperties *audioProperties() const;
+
+    /*!
+     * Returns a pointer to the file represented by this handler class.
+     *
+     * As a general rule this call should be avoided since if you need to work
+     * with file objects directly, you are probably better served instantiating
+     * the File subclasses (i.e. MPEG::File) manually and working with their APIs.
+     *
+     * This <i>handle</i> exists to provide a minimal, generic and value-based
+     * wrapper around a File.  Accessing the file directly generally indicates
+     * a moving away from this simplicity (and into things beyond the scope of
+     * FileRef).
+     *
+     * \warning This pointer will become invalid when this FileRef and all
+     * copies pass out of scope.
+     */
+    File *file() const;
+
+    /*!
+     * Saves the file.  Returns true on success.
+     */
+    bool save();
+
+    /*!
+     * Adds a FileTypeResolver to the list of those used by TagLib.  Each
+     * additional FileTypeResolver is added to the front of a list of resolvers
+     * that are tried.  If the FileTypeResolver returns zero the next resolver
+     * is tried.
+     *
+     * Returns a pointer to the added resolver (the same one that's passed in --
+     * this is mostly so that static inialializers have something to use for
+     * assignment).
+     *
+     * \see FileTypeResolver
+     */
+    static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver);
+
+    /*!
+     * As is mentioned elsewhere in this class's documentation, the default file
+     * type resolution code provided by TagLib only works by comparing file
+     * extensions.
+     *
+     * This method returns the list of file extensions that are used by default.
+     *
+     * The extensions are all returned in lowercase, though the comparison used
+     * by TagLib for resolution is case-insensitive.
+     *
+     * \note This does not account for any additional file type resolvers that
+     * are plugged in.  Also note that this is not intended to replace a propper
+     * mime-type resolution system, but is just here for reference.
+     *
+     * \see FileTypeResolver
+     */
+    static StringList defaultFileExtensions();
+
+    /*!
+     * Returns true if the file (and as such other pointers) are null.
+     */
+    bool isNull() const;
+
+    /*!
+     * Assign the file pointed to by \a ref to this FileRef.
+     */
+    FileRef &operator=(const FileRef &ref);
+
+    /*!
+     * Returns true if this FileRef and \a ref point to the same File object.
+     */
+    bool operator==(const FileRef &ref) const;
+
+    /*!
+     * Returns true if this FileRef and \a ref do not point to the same File
+     * object.
+     */
+    bool operator!=(const FileRef &ref) const;
+
+    /*!
+     * A simple implementation of file type guessing.  If \a readAudioProperties
+     * is true then the audio properties will be read using
+     * \a audioPropertiesStyle.  If \a readAudioProperties is false then
+     * \a audioPropertiesStyle will be ignored.
+     *
+     * \note You generally shouldn't use this method, but instead the constructor
+     * directly.
+     *
+     * \deprecated
+     */
+    static File *create(FileName fileName,
+                        bool readAudioProperties = true,
+                        AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
+
+
+  private:
+    class FileRefPrivate;
+    FileRefPrivate *d;
+  };
+
+} // namespace TagLib
+
+#endif
diff --git a/src/taglib/flac/flacfile.cpp b/src/taglib/flac/flacfile.cpp
new file mode 100644 (file)
index 0000000..7f3d902
--- /dev/null
@@ -0,0 +1,504 @@
+/***************************************************************************
+    copyright            : (C) 2003-2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <tbytevector.h>
+#include <tstring.h>
+#include <tlist.h>
+#include <tdebug.h>
+#include <tagunion.h>
+
+#include <id3v2header.h>
+#include <id3v2tag.h>
+#include <id3v1tag.h>
+#include <xiphcomment.h>
+
+#include "flacfile.h"
+
+using namespace TagLib;
+
+namespace
+{
+  enum { XiphIndex = 0, ID3v2Index = 1, ID3v1Index = 2 };
+  enum { StreamInfo = 0, Padding, Application, SeekTable, VorbisComment, CueSheet };
+  enum { MinPaddingLength = 4096 };
+}
+
+class FLAC::File::FilePrivate
+{
+public:
+  FilePrivate() :
+    ID3v2FrameFactory(ID3v2::FrameFactory::instance()),
+    ID3v2Location(-1),
+    ID3v2OriginalSize(0),
+    ID3v1Location(-1),
+    properties(0),
+    flacStart(0),
+    streamStart(0),
+    streamLength(0),
+    scanned(false),
+    hasXiphComment(false),
+    hasID3v2(false),
+    hasID3v1(false) {}
+
+  ~FilePrivate()
+  {
+    delete properties;
+  }
+
+  const ID3v2::FrameFactory *ID3v2FrameFactory;
+  long ID3v2Location;
+  uint ID3v2OriginalSize;
+
+  long ID3v1Location;
+
+  TagUnion tag;
+
+  Properties *properties;
+  ByteVector streamInfoData;
+  ByteVector xiphCommentData;
+
+  long flacStart;
+  long streamStart;
+  long streamLength;
+  bool scanned;
+
+  bool hasXiphComment;
+  bool hasID3v2;
+  bool hasID3v1;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+FLAC::File::File(FileName file, bool readProperties,
+                 Properties::ReadStyle propertiesStyle) :
+  TagLib::File(file)
+{
+  d = new FilePrivate;
+  read(readProperties, propertiesStyle);
+}
+
+FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
+                 bool readProperties, Properties::ReadStyle propertiesStyle) :
+  TagLib::File(file)
+{
+  d = new FilePrivate;
+  d->ID3v2FrameFactory = frameFactory;
+  read(readProperties, propertiesStyle);
+}
+
+FLAC::File::~File()
+{
+  delete d;
+}
+
+TagLib::Tag *FLAC::File::tag() const
+{
+  return &d->tag;
+}
+
+FLAC::Properties *FLAC::File::audioProperties() const
+{
+  return d->properties;
+}
+
+
+bool FLAC::File::save()
+{
+  if(readOnly()) {
+    debug("FLAC::File::save() - Cannot save to a read only file.");
+    return false;
+  }
+
+  // Create new vorbis comments
+
+  Tag::duplicate(&d->tag, xiphComment(true), true);
+
+  d->xiphCommentData = xiphComment()->render(false);
+
+  // A Xiph comment portion of the data stream starts with a 4-byte descriptor.
+  // The first byte indicates the frame type.  The last three bytes are used
+  // to give the length of the data segment.  Here we start
+
+  ByteVector data = ByteVector::fromUInt(d->xiphCommentData.size());
+
+  data[0] = char(VorbisComment);
+  data.append(d->xiphCommentData);
+
+
+   // If file already have comment => find and update it
+   // if not => insert one
+
+   // TODO: Search for padding and use that
+
+  if(d->hasXiphComment) {
+
+    long nextBlockOffset = d->flacStart;
+    bool isLastBlock = false;
+
+    while(!isLastBlock) {
+      seek(nextBlockOffset);
+
+      ByteVector header = readBlock(4);
+      char blockType = header[0] & 0x7f;
+      isLastBlock = (header[0] & 0x80) != 0;
+      uint blockLength = header.mid(1, 3).toUInt();
+
+      if(blockType == VorbisComment) {
+
+        long paddingBreak = 0;
+
+        if(!isLastBlock) {
+          paddingBreak = findPaddingBreak(nextBlockOffset + blockLength + 4,
+                                          nextBlockOffset + d->xiphCommentData.size() + 8,
+                                          &isLastBlock);
+        }
+
+        uint paddingLength = 0;
+
+         if(paddingBreak) {
+
+           // There is space for comment and padding blocks without rewriting the
+           // whole file.  Note: This cannot overflow.
+
+           paddingLength = paddingBreak - (nextBlockOffset + d->xiphCommentData.size() + 8);
+         }
+         else {
+
+           // Not enough space, so we will have to rewrite the whole file
+           // following this block
+
+           paddingLength = d->xiphCommentData.size();
+
+           if(paddingLength < MinPaddingLength)
+             paddingLength = MinPaddingLength;
+
+           paddingBreak = nextBlockOffset + blockLength + 4;
+         }
+
+         ByteVector padding = ByteVector::fromUInt(paddingLength);
+
+         padding[0] = 1;
+
+         if(isLastBlock)
+           padding[0] |= 0x80;
+
+         padding.resize(paddingLength + 4);
+         ByteVector pair(data);
+         pair.append(padding);
+         insert(pair, nextBlockOffset, paddingBreak - nextBlockOffset);
+         break;
+      }
+
+      nextBlockOffset += blockLength + 4;
+    }
+  }
+  else {
+
+    const long firstBlockOffset = d->flacStart;
+    seek(firstBlockOffset);
+
+    ByteVector header = readBlock(4);
+    bool isLastBlock = (header[0] & 0x80) != 0;
+    uint blockLength = header.mid(1, 3).toUInt();
+
+    if(isLastBlock) {
+
+      // If the first block was previously also the last block, then we want to
+      // mark it as no longer being the first block (the writeBlock() call) and
+      // then set the data for the block that we're about to write to mark our
+      // new block as the last block.
+
+      seek(firstBlockOffset);
+      writeBlock(static_cast<char>(header[0] & 0x7F));
+      data[0] |= 0x80;
+    }
+
+    insert(data, firstBlockOffset + blockLength + 4, 0);
+    d->hasXiphComment = true;
+  }
+
+  // Update ID3 tags
+
+  if(ID3v2Tag()) {
+    if(d->hasID3v2) {
+      if(d->ID3v2Location < d->flacStart)
+        debug("FLAC::File::save() -- This can't be right -- an ID3v2 tag after the "
+              "start of the FLAC bytestream?  Not writing the ID3v2 tag.");
+      else
+        insert(ID3v2Tag()->render(), d->ID3v2Location, d->ID3v2OriginalSize);
+    }
+    else
+      insert(ID3v2Tag()->render(), 0, 0);
+  }
+
+  if(ID3v1Tag()) {
+    seek(-128, End);
+    writeBlock(ID3v1Tag()->render());
+  }
+
+  return true;
+}
+
+ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
+{
+  if(!create || d->tag[ID3v2Index])
+    return static_cast<ID3v2::Tag *>(d->tag[ID3v2Index]);
+
+  d->tag.set(ID3v2Index, new ID3v2::Tag);
+  return static_cast<ID3v2::Tag *>(d->tag[ID3v2Index]);
+}
+
+ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
+{
+  return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
+}
+
+Ogg::XiphComment *FLAC::File::xiphComment(bool create)
+{
+  return d->tag.access<Ogg::XiphComment>(XiphIndex, create);
+}
+
+void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
+{
+  d->ID3v2FrameFactory = factory;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
+{
+  // Look for an ID3v2 tag
+
+  d->ID3v2Location = findID3v2();
+
+  if(d->ID3v2Location >= 0) {
+
+    d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
+
+    d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
+
+    if(ID3v2Tag()->header()->tagSize() <= 0)
+      d->tag.set(ID3v2Index, 0);
+    else
+      d->hasID3v2 = true;
+  }
+
+  // Look for an ID3v1 tag
+
+  d->ID3v1Location = findID3v1();
+
+  if(d->ID3v1Location >= 0) {
+    d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
+    d->hasID3v1 = true;
+  }
+
+  // Look for FLAC metadata, including vorbis comments
+
+  scan();
+
+  if(!isValid())
+    return;
+
+  if(d->hasXiphComment)
+    d->tag.set(XiphIndex, new Ogg::XiphComment(xiphCommentData()));
+  else
+    d->tag.set(XiphIndex, new Ogg::XiphComment);
+
+  if(readProperties)
+    d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle);
+}
+
+ByteVector FLAC::File::streamInfoData()
+{
+  return isValid() ? d->streamInfoData : ByteVector();
+}
+
+ByteVector FLAC::File::xiphCommentData() const
+{
+  return (isValid() && d->hasXiphComment) ? d->xiphCommentData : ByteVector();
+}
+
+long FLAC::File::streamLength()
+{
+  return d->streamLength;
+}
+
+void FLAC::File::scan()
+{
+  // Scan the metadata pages
+
+  if(d->scanned)
+    return;
+
+  if(!isValid())
+    return;
+
+  long nextBlockOffset;
+
+  if(d->hasID3v2)
+    nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
+  else
+    nextBlockOffset = find("fLaC");
+
+  if(nextBlockOffset < 0) {
+    debug("FLAC::File::scan() -- FLAC stream not found");
+    setValid(false);
+    return;
+  }
+
+  nextBlockOffset += 4;
+  d->flacStart = nextBlockOffset;
+
+  seek(nextBlockOffset);
+
+  ByteVector header = readBlock(4);
+
+  // Header format (from spec):
+  // <1> Last-metadata-block flag
+  // <7> BLOCK_TYPE
+  //    0 : STREAMINFO
+  //    1 : PADDING
+  //    ..
+  //    4 : VORBIS_COMMENT
+  //    ..
+  // <24> Length of metadata to follow
+
+  char blockType = header[0] & 0x7f;
+  bool isLastBlock = (header[0] & 0x80) != 0;
+  uint length = header.mid(1, 3).toUInt();
+
+  // First block should be the stream_info metadata
+
+  if(blockType != StreamInfo) {
+    debug("FLAC::File::scan() -- invalid FLAC stream");
+    setValid(false);
+    return;
+  }
+
+  d->streamInfoData = readBlock(length);
+  nextBlockOffset += length + 4;
+
+  // Search through the remaining metadata
+  while(!isLastBlock) {
+
+    header = readBlock(4);
+    blockType = header[0] & 0x7f;
+    isLastBlock = (header[0] & 0x80) != 0;
+    length = header.mid(1, 3).toUInt();
+
+    // Found the vorbis-comment
+    if(blockType == VorbisComment) {
+      if(!d->hasXiphComment) {
+        d->xiphCommentData = readBlock(length);
+        d->hasXiphComment = true;
+      }
+      else {
+        debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one");
+      }
+    }
+
+    nextBlockOffset += length + 4;
+
+    if(nextBlockOffset >= File::length()) {
+      debug("FLAC::File::scan() -- FLAC stream corrupted");
+      setValid(false);
+      return;
+    }
+    seek(nextBlockOffset);
+  }
+
+  // End of metadata, now comes the datastream
+
+  d->streamStart = nextBlockOffset;
+  d->streamLength = File::length() - d->streamStart;
+
+  if(d->hasID3v1)
+    d->streamLength -= 128;
+
+  d->scanned = true;
+}
+
+long FLAC::File::findID3v1()
+{
+  if(!isValid())
+    return -1;
+
+  seek(-128, End);
+  long p = tell();
+
+  if(readBlock(3) == ID3v1::Tag::fileIdentifier())
+    return p;
+
+  return -1;
+}
+
+long FLAC::File::findID3v2()
+{
+  if(!isValid())
+    return -1;
+
+  seek(0);
+
+  if(readBlock(3) == ID3v2::Header::fileIdentifier())
+    return 0;
+
+  return -1;
+}
+
+long FLAC::File::findPaddingBreak(long nextBlockOffset, long targetOffset, bool *isLast)
+{
+  // Starting from nextBlockOffset, step over padding blocks to find the
+  // address of a block which is after targetOffset. Return zero if
+  // a non-padding block occurs before that point.
+
+  while(true) {
+    seek(nextBlockOffset);
+
+    ByteVector header = readBlock(4);
+    char blockType = header[0] & 0x7f;
+    bool isLastBlock = header[0] & 0x80;
+    uint length = header.mid(1, 3).toUInt();
+
+    if(blockType != Padding)
+      break;
+
+    nextBlockOffset += 4 + length;
+
+    if(nextBlockOffset >= targetOffset) {
+      *isLast = isLastBlock;
+      return nextBlockOffset;
+    }
+
+    if(isLastBlock)
+      break;
+  }
+
+  return 0;
+}
diff --git a/src/taglib/flac/flacfile.h b/src/taglib/flac/flacfile.h
new file mode 100644 (file)
index 0000000..015ecc8
--- /dev/null
@@ -0,0 +1,202 @@
+/***************************************************************************
+    copyright            : (C) 2003 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_FLACFILE_H
+#define TAGLIB_FLACFILE_H
+
+#include "taglib_export.h"
+#include "tfile.h"
+
+#include "flacproperties.h"
+
+namespace TagLib {
+
+  class Tag;
+
+  namespace ID3v2 { class FrameFactory; class Tag; }
+  namespace ID3v1 { class Tag; }
+  namespace Ogg { class XiphComment; }
+
+  //! An implementation of FLAC metadata
+
+  /*!
+   * This is implementation of FLAC metadata for non-Ogg FLAC files.  At some
+   * point when Ogg / FLAC is more common there will be a similar implementation
+   * under the Ogg hiearchy.
+   *
+   * This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream
+   * properties from the file.
+   */
+
+  namespace FLAC {
+
+    //! An implementation of TagLib::File with FLAC specific methods
+
+    /*!
+     * This implements and provides an interface for FLAC files to the
+     * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
+     * the abstract TagLib::File API as well as providing some additional
+     * information specific to FLAC files.
+     */
+
+    class TAGLIB_EXPORT File : public TagLib::File
+    {
+    public:
+      /*!
+       * Contructs a FLAC file from \a file.  If \a readProperties is true the
+       * file's audio properties will also be read using \a propertiesStyle.  If
+       * false, \a propertiesStyle is ignored.
+       *
+       * \deprecated This constructor will be dropped in favor of the one below
+       * in a future version.
+       */
+      File(FileName file, bool readProperties = true,
+           Properties::ReadStyle propertiesStyle = Properties::Average);
+
+      /*!
+       * Contructs a FLAC file from \a file.  If \a readProperties is true the
+       * file's audio properties will also be read using \a propertiesStyle.  If
+       * false, \a propertiesStyle is ignored.
+       *
+       * If this file contains and ID3v2 tag the frames will be created using
+       * \a frameFactory.
+       */
+      // BIC: merge with the above constructor
+      File(FileName file, ID3v2::FrameFactory *frameFactory,
+           bool readProperties = true,
+           Properties::ReadStyle propertiesStyle = Properties::Average);
+
+      /*!
+       * Destroys this instance of the File.
+       */
+      virtual ~File();
+
+      /*!
+       * Returns the Tag for this file.  This will be a union of XiphComment,
+       * ID3v1 and ID3v2 tags.
+       *
+       * \see ID3v2Tag()
+       * \see ID3v1Tag()
+       * \see XiphComment()
+       */
+      virtual TagLib::Tag *tag() const;
+
+      /*!
+       * Returns the FLAC::Properties for this file.  If no audio properties
+       * were read then this will return a null pointer.
+       */
+      virtual Properties *audioProperties() const;
+
+      /*!
+       * Save the file.  This will primarily save the XiphComment, but
+       * will also keep any old ID3-tags up to date. If the file
+       * has no XiphComment, one will be constructed from the ID3-tags.
+       *
+       * This returns true if the save was successful.
+       */
+      virtual bool save();
+
+      /*!
+       * Returns a pointer to the ID3v2 tag of the file.
+       *
+       * If \a create is false (the default) this will return a null pointer
+       * if there is no valid ID3v2 tag.  If \a create is true it will create
+       * an ID3v2 tag if one does not exist.
+       *
+       * \note The Tag <b>is still</b> owned by the FLAC::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      ID3v2::Tag *ID3v2Tag(bool create = false);
+
+      /*!
+       * Returns a pointer to the ID3v1 tag of the file.
+       *
+       * If \a create is false (the default) this will return a null pointer
+       * if there is no valid ID3v1 tag.  If \a create is true it will create
+       * an ID3v1 tag if one does not exist.
+       *
+       * \note The Tag <b>is still</b> owned by the FLAC::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      ID3v1::Tag *ID3v1Tag(bool create = false);
+
+      /*!
+       * Returns a pointer to the XiphComment for the file.
+       *
+       * If \a create is false (the default) this will return a null pointer
+       * if there is no valid XiphComment.  If \a create is true it will create
+       * a XiphComment if one does not exist.
+       *
+       * \note The Tag <b>is still</b> owned by the FLAC::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      Ogg::XiphComment *xiphComment(bool create = false);
+
+      /*!
+       * Set the ID3v2::FrameFactory to something other than the default.  This
+       * can be used to specify the way that ID3v2 frames will be interpreted
+       * when
+       *
+       * \see ID3v2FrameFactory
+       */
+      void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
+
+      /*!
+       * Returns the block of data used by FLAC::Properties for parsing the
+       * stream properties.
+       *
+       * \deprecated This method will not be public in a future release.
+       */
+      ByteVector streamInfoData(); // BIC: remove
+
+      /*!
+       * Returns the length of the audio-stream, used by FLAC::Properties for
+       * calculating the bitrate.
+       *
+       * \deprecated This method will not be public in a future release.
+       */
+      long streamLength();  // BIC: remove
+
+    private:
+      File(const File &);
+      File &operator=(const File &);
+
+      void read(bool readProperties, Properties::ReadStyle propertiesStyle);
+      void scan();
+      long findID3v2();
+      long findID3v1();
+      ByteVector xiphCommentData() const;
+      long findPaddingBreak(long nextPageOffset, long targetOffset, bool *isLast);
+
+      class FilePrivate;
+      FilePrivate *d;
+    };
+  }
+}
+
+#endif
diff --git a/src/taglib/flac/flacproperties.cpp b/src/taglib/flac/flacproperties.cpp
new file mode 100644 (file)
index 0000000..f137059
--- /dev/null
@@ -0,0 +1,150 @@
+/***************************************************************************
+    copyright            : (C) 2003 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <tstring.h>
+#include <tdebug.h>
+
+#include "flacproperties.h"
+#include "flacfile.h"
+
+using namespace TagLib;
+
+class FLAC::Properties::PropertiesPrivate
+{
+public:
+  PropertiesPrivate(ByteVector d, long st, ReadStyle s) :
+    data(d),
+    streamLength(st),
+    style(s),
+    length(0),
+    bitrate(0),
+    sampleRate(0),
+    sampleWidth(0),
+    channels(0) {}
+
+  ByteVector data;
+  long streamLength;
+  ReadStyle style;
+  int length;
+  int bitrate;
+  int sampleRate;
+  int sampleWidth;
+  int channels;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style)
+{
+  d = new PropertiesPrivate(data, streamLength, style);
+  read();
+}
+
+FLAC::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
+{
+  d = new PropertiesPrivate(file->streamInfoData(), file->streamLength(), style);
+  read();
+}
+
+FLAC::Properties::~Properties()
+{
+  delete d;
+}
+
+int FLAC::Properties::length() const
+{
+  return d->length;
+}
+
+int FLAC::Properties::bitrate() const
+{
+  return d->bitrate;
+}
+
+int FLAC::Properties::sampleRate() const
+{
+  return d->sampleRate;
+}
+
+int FLAC::Properties::sampleWidth() const
+{
+  return d->sampleWidth;
+}
+
+int FLAC::Properties::channels() const
+{
+  return d->channels;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+void FLAC::Properties::read()
+{
+  if(d->data.size() < 18) {
+    debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
+    return;
+  }
+
+  int pos = 0;
+
+  // Minimum block size (in samples)
+  pos += 2;
+
+  // Maximum block size (in samples)
+  pos += 2;
+
+  // Minimum frame size (in bytes)
+  pos += 3;
+
+  // Maximum frame size (in bytes)
+  pos += 3;
+
+  uint flags = d->data.mid(pos, 4).toUInt(true);
+  d->sampleRate = flags >> 12;
+  d->channels = ((flags >> 9) & 7) + 1;
+  d->sampleWidth = ((flags >> 4) & 31) + 1;
+
+  // The last 4 bits are the most significant 4 bits for the 36 bit
+  // stream length in samples. (Audio files measured in days)
+
+  uint highLength =d->sampleRate > 0 ? (((flags & 0xf) << 28) / d->sampleRate) << 4 : 0;
+  pos += 4;
+
+  d->length = d->sampleRate > 0 ?
+      (d->data.mid(pos, 4).toUInt(true)) / d->sampleRate + highLength : 0;
+  pos += 4;
+
+  // Uncompressed bitrate:
+
+  //d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth;
+
+  // Real bitrate:
+
+  d->bitrate = d->length > 0 ? ((d->streamLength * 8UL) / d->length) / 1000 : 0;
+}
diff --git a/src/taglib/flac/flacproperties.h b/src/taglib/flac/flacproperties.h
new file mode 100644 (file)
index 0000000..9ac6766
--- /dev/null
@@ -0,0 +1,92 @@
+/***************************************************************************
+    copyright            : (C) 2003 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_FLACPROPERTIES_H
+#define TAGLIB_FLACPROPERTIES_H
+
+#include "taglib_export.h"
+#include "audioproperties.h"
+
+namespace TagLib {
+
+  namespace FLAC {
+
+    class File;
+
+    //! An implementation of audio property reading for FLAC
+
+    /*!
+     * This reads the data from an FLAC stream found in the AudioProperties
+     * API.
+     */
+
+    class TAGLIB_EXPORT Properties : public AudioProperties
+    {
+    public:
+      /*!
+       * Create an instance of FLAC::Properties with the data read from the
+       * ByteVector \a data.
+       */
+       // BIC: switch to const reference
+      Properties(ByteVector data, long streamLength, ReadStyle style = Average);
+
+      /*!
+       * Create an instance of FLAC::Properties with the data read from the
+       * FLAC::File \a file.
+       */
+       // BIC: remove
+      Properties(File *file, ReadStyle style = Average);
+
+      /*!
+       * Destroys this FLAC::Properties instance.
+       */
+      virtual ~Properties();
+
+      // Reimplementations.
+
+      virtual int length() const;
+      virtual int bitrate() const;
+      virtual int sampleRate() const;
+      virtual int channels() const;
+
+      /*!
+       * Returns the sample width as read from the FLAC identification
+       * header.
+       */
+      int sampleWidth() const;
+
+    private:
+      Properties(const Properties &);
+      Properties &operator=(const Properties &);
+
+      void read();
+
+      class PropertiesPrivate;
+      PropertiesPrivate *d;
+    };
+  }
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4atom.cpp b/src/taglib/mp4/mp4atom.cpp
new file mode 100644 (file)
index 0000000..6d86a6e
--- /dev/null
@@ -0,0 +1,197 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_MP4
+
+#include <tdebug.h>
+#include <tstring.h>
+#include "mp4atom.h"
+
+using namespace TagLib;
+
+const char *MP4::Atom::containers[10] = {
+    "moov", "udta", "mdia", "meta", "ilst",
+    "stbl", "minf", "moof", "traf", "trak",
+};
+
+MP4::Atom::Atom(File *file)
+{
+  offset = file->tell();
+  ByteVector header = file->readBlock(8);
+  if (header.size() != 8) {
+    // The atom header must be 8 bytes long, otherwise there is either
+    // trailing garbage or the file is truncated
+    debug("MP4: Couldn't read 8 bytes of data for atom header");
+    length = 0;
+    file->seek(0, File::End);
+    return;
+  }
+
+  length = header.mid(0, 4).toUInt();
+
+  if (length == 1) {
+    long long longLength = file->readBlock(8).toLongLong();
+    if (longLength >= 8 && longLength <= 0xFFFFFFFF) {
+        // The atom has a 64-bit length, but it's actually a 32-bit value
+        length = (long)longLength;
+    }
+    else {
+        debug("MP4: 64-bit atoms are not supported");
+        length = 0;
+        file->seek(0, File::End);
+        return;
+    }
+  }
+  if (length < 8) {
+    debug("MP4: Invalid atom size");
+    length = 0;
+    file->seek(0, File::End);
+    return;
+  }
+
+  name = header.mid(4, 4);
+
+  for(int i = 0; i < numContainers; i++) {
+    if(name == containers[i]) {
+      if(name == "meta") {
+        file->seek(4, File::Current);
+      }
+      while(file->tell() < offset + length) {
+        MP4::Atom *child = new MP4::Atom(file);
+        children.append(child);
+        if (child->length == 0)
+          return;
+      }
+      return;
+    }
+  }
+
+  file->seek(offset + length);
+}
+
+MP4::Atom::~Atom()
+{
+  for(unsigned int i = 0; i < children.size(); i++) {
+    delete children[i];
+  }
+  children.clear();
+}
+
+MP4::Atom *
+MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
+{
+  if(name1 == 0) {
+    return this;
+  }
+  for(unsigned int i = 0; i < children.size(); i++) {
+    if(children[i]->name == name1) {
+      return children[i]->find(name2, name3, name4);
+    }
+  }
+  return 0;
+}
+
+MP4::AtomList
+MP4::Atom::findall(const char *name, bool recursive)
+{
+  MP4::AtomList result;
+  for(unsigned int i = 0; i < children.size(); i++) {
+    if(children[i]->name == name) {
+      result.append(children[i]);
+    }
+    if(recursive) {
+      result.append(children[i]->findall(name, recursive));
+    }
+  }
+  return result;
+}
+
+bool
+MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
+{
+  path.append(this);
+  if(name1 == 0) {
+    return true;
+  }
+  for(unsigned int i = 0; i < children.size(); i++) {
+    if(children[i]->name == name1) {
+      return children[i]->path(path, name2, name3);
+    }
+  }
+  return false;
+}
+
+MP4::Atoms::Atoms(File *file)
+{
+  file->seek(0, File::End);
+  long end = file->tell();
+  file->seek(0);
+  while(file->tell() + 8 <= end) {
+    MP4::Atom *atom = new MP4::Atom(file);
+    atoms.append(atom);
+    if (atom->length == 0)
+      break;
+  }
+}
+
+MP4::Atoms::~Atoms()
+{
+  for(unsigned int i = 0; i < atoms.size(); i++) {
+    delete atoms[i];
+  }
+  atoms.clear();
+}
+
+MP4::Atom *
+MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
+{
+  for(unsigned int i = 0; i < atoms.size(); i++) {
+    if(atoms[i]->name == name1) {
+      return atoms[i]->find(name2, name3, name4);
+    }
+  }
+  return 0;
+}
+
+MP4::AtomList
+MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
+{
+  MP4::AtomList path;
+  for(unsigned int i = 0; i < atoms.size(); i++) {
+    if(atoms[i]->name == name1) {
+      if(!atoms[i]->path(path, name2, name3, name4)) {
+        path.clear();
+      }
+      return path;
+    }
+  }
+  return path;
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4atom.h b/src/taglib/mp4/mp4atom.h
new file mode 100644 (file)
index 0000000..a918561
--- /dev/null
@@ -0,0 +1,77 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+// This file is not part of the public API!
+
+#ifndef DO_NOT_DOCUMENT
+
+#ifndef TAGLIB_MP4ATOM_H
+#define TAGLIB_MP4ATOM_H
+
+#include "tfile.h"
+#include "tlist.h"
+
+namespace TagLib {
+
+  namespace MP4 {
+
+    class Atom;
+    typedef TagLib::List<Atom *> AtomList;
+
+    class Atom
+    {
+    public:
+        Atom(File *file);
+        ~Atom();
+        Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
+        bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0);
+        AtomList findall(const char *name, bool recursive = false);
+        long offset;
+        long length;
+        TagLib::ByteVector name;
+        AtomList children;
+    private:
+        static const int numContainers = 10;
+        static const char *containers[10];
+    };
+
+    //! Root-level atoms
+    class Atoms
+    {
+    public:
+        Atoms(File *file);
+        ~Atoms();
+        Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
+        AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
+        AtomList atoms;
+    };
+
+  }
+
+}
+
+#endif
+
+#endif
diff --git a/src/taglib/mp4/mp4coverart.cpp b/src/taglib/mp4/mp4coverart.cpp
new file mode 100644 (file)
index 0000000..983df02
--- /dev/null
@@ -0,0 +1,89 @@
+/**************************************************************************
+    copyright            : (C) 2009 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_MP4
+
+#include <taglib.h>
+#include <tdebug.h>
+#include "mp4coverart.h"
+
+using namespace TagLib;
+
+class MP4::CoverArt::CoverArtPrivate : public RefCounter
+{
+public:
+  CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {}
+
+  Format format;
+  ByteVector data;
+};
+
+MP4::CoverArt::CoverArt(Format format, const ByteVector &data)
+{
+  d = new CoverArtPrivate;
+  d->format = format;
+  d->data = data;
+}
+
+MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d)
+{
+  d->ref();
+}
+
+MP4::CoverArt &
+MP4::CoverArt::operator=(const CoverArt &item)
+{
+  if(d->deref()) {
+    delete d;
+  }
+  d = item.d;
+  d->ref();
+  return *this;
+}
+
+MP4::CoverArt::~CoverArt()
+{
+  if(d->deref()) {
+    delete d;
+  }
+}
+
+MP4::CoverArt::Format
+MP4::CoverArt::format() const
+{
+  return d->format;
+}
+
+ByteVector
+MP4::CoverArt::data() const
+{
+  return d->data;
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4coverart.h b/src/taglib/mp4/mp4coverart.h
new file mode 100644 (file)
index 0000000..00a7aff
--- /dev/null
@@ -0,0 +1,71 @@
+/**************************************************************************
+    copyright            : (C) 2009 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MP4COVERART_H
+#define TAGLIB_MP4COVERART_H
+
+#include "tlist.h"
+#include "tbytevector.h"
+#include "taglib_export.h"
+
+namespace TagLib {
+
+  namespace MP4 {
+
+    class TAGLIB_EXPORT CoverArt
+    {
+    public:
+      /*!
+       * This describes the image type.
+       */
+      enum Format {
+        JPEG = 0x0D,
+        PNG  = 0x0E
+      };
+
+      CoverArt(Format format, const ByteVector &data);
+      ~CoverArt();
+
+      CoverArt(const CoverArt &item);
+      CoverArt &operator=(const CoverArt &item);
+
+      //! Format of the image
+      Format format() const;
+
+      //! The image data
+      ByteVector data() const;
+
+    private:
+      class CoverArtPrivate;
+      CoverArtPrivate *d;
+    };
+
+    typedef List<CoverArt> CoverArtList;
+
+  }
+
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4file.cpp b/src/taglib/mp4/mp4file.cpp
new file mode 100644 (file)
index 0000000..21a5429
--- /dev/null
@@ -0,0 +1,138 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_MP4
+
+#include <tdebug.h>
+#include <tstring.h>
+#include "mp4atom.h"
+#include "mp4tag.h"
+#include "mp4file.h"
+
+using namespace TagLib;
+
+class MP4::File::FilePrivate
+{
+public:
+  FilePrivate() : tag(0), atoms(0), properties(0)
+  {
+  }
+
+  ~FilePrivate()
+  {
+    if(atoms) {
+        delete atoms;
+        atoms = 0;
+    }
+    if(tag) {
+        delete tag;
+        tag = 0;
+    }
+    if(properties) {
+        delete properties;
+        properties = 0;
+    }
+  }
+
+  MP4::Tag *tag;
+  MP4::Atoms *atoms;
+  MP4::Properties *properties;
+};
+
+MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
+    : TagLib::File(file)
+{
+  d = new FilePrivate;
+  read(readProperties, audioPropertiesStyle);
+}
+
+MP4::File::~File()
+{
+  delete d;
+}
+
+MP4::Tag *
+MP4::File::tag() const
+{
+  return d->tag;
+}
+
+MP4::Properties *
+MP4::File::audioProperties() const
+{
+  return d->properties;
+}
+
+bool
+MP4::File::checkValid(const MP4::AtomList &list)
+{
+  for(uint i = 0; i < list.size(); i++) {
+    if(list[i]->length == 0)
+      return false;
+    if(!checkValid(list[i]->children))
+      return false;
+  }
+  return true;
+}
+
+void
+MP4::File::read(bool readProperties, Properties::ReadStyle audioPropertiesStyle)
+{
+  if(!isValid())
+    return;
+
+  d->atoms = new Atoms(this);
+  if (!checkValid(d->atoms->atoms)) {
+    setValid(false);
+    return;
+  }
+
+  // must have a moov atom, otherwise consider it invalid
+  MP4::Atom *moov = d->atoms->find("moov");
+  if(!moov) {
+    setValid(false);
+    return;
+  }
+
+  d->tag = new Tag(this, d->atoms);
+  if(readProperties) {
+    d->properties = new Properties(this, d->atoms, audioPropertiesStyle);
+  }
+}
+
+bool
+MP4::File::save()
+{
+  if(!isValid())
+    return false;
+
+  return d->tag->save();
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4file.h b/src/taglib/mp4/mp4file.h
new file mode 100644 (file)
index 0000000..333551a
--- /dev/null
@@ -0,0 +1,103 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MP4FILE_H
+#define TAGLIB_MP4FILE_H
+
+#include "tag.h"
+#include "tfile.h"
+#include "taglib_export.h"
+#include "mp4properties.h"
+#include "mp4tag.h"
+
+namespace TagLib {
+
+  //! An implementation of MP4 (AAC, ALAC, ...) metadata
+  namespace MP4 {
+
+    class Atoms;
+
+    /*!
+     * This implements and provides an interface for MP4 files to the
+     * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
+     * the abstract TagLib::File API as well as providing some additional
+     * information specific to MP4 files.
+     */
+    class TAGLIB_EXPORT File : public TagLib::File
+    {
+    public:
+      /*!
+       * Contructs a MP4 file from \a file.  If \a readProperties is true the
+       * file's audio properties will also be read using \a propertiesStyle.  If
+       * false, \a propertiesStyle is ignored.
+       *
+       * \note In the current implementation, both \a readProperties and
+       * \a propertiesStyle are ignored.
+       */
+      File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
+
+      /*!
+       * Destroys this instance of the File.
+       */
+      virtual ~File();
+
+      /*!
+       * Returns a pointer to the MP4 tag of the file.
+       *
+       * MP4::Tag implements the tag interface, so this serves as the
+       * reimplementation of TagLib::File::tag().
+       *
+       * \note The Tag <b>is still</b> owned by the MP4::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      Tag *tag() const;
+
+      /*!
+       * Returns the MP4 audio properties for this file.
+       */
+      Properties *audioProperties() const;
+
+      /*!
+       * Save the file.
+       *
+       * This returns true if the save was successful.
+       */
+      bool save();
+
+    private:
+
+      void read(bool readProperties, Properties::ReadStyle audioPropertiesStyle);
+      bool checkValid(const MP4::AtomList &list);
+
+      class FilePrivate;
+      FilePrivate *d;
+    };
+
+  }
+
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4item.cpp b/src/taglib/mp4/mp4item.cpp
new file mode 100644 (file)
index 0000000..0af331f
--- /dev/null
@@ -0,0 +1,149 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_MP4
+
+#include <taglib.h>
+#include <tdebug.h>
+#include "mp4item.h"
+
+using namespace TagLib;
+
+class MP4::Item::ItemPrivate : public RefCounter
+{
+public:
+  ItemPrivate() : RefCounter(), valid(true) {}
+
+  bool valid;
+  union {
+    bool m_bool;
+    int m_int;
+    IntPair m_intPair;
+  };
+  StringList m_stringList;
+  MP4::CoverArtList m_coverArtList;
+};
+
+MP4::Item::Item()
+{
+  d = new ItemPrivate;
+  d->valid = false;
+}
+
+MP4::Item::Item(const Item &item) : d(item.d)
+{
+  d->ref();
+}
+
+MP4::Item &
+MP4::Item::operator=(const Item &item)
+{
+  if(d->deref()) {
+    delete d;
+  }
+  d = item.d;
+  d->ref();
+  return *this;
+}
+
+MP4::Item::~Item()
+{
+  if(d->deref()) {
+    delete d;
+  }
+}
+
+MP4::Item::Item(bool value)
+{
+  d = new ItemPrivate;
+  d->m_bool = value;
+}
+
+MP4::Item::Item(int value)
+{
+  d = new ItemPrivate;
+  d->m_int = value;
+}
+
+MP4::Item::Item(int value1, int value2)
+{
+  d = new ItemPrivate;
+  d->m_intPair.first = value1;
+  d->m_intPair.second = value2;
+}
+
+MP4::Item::Item(const StringList &value)
+{
+  d = new ItemPrivate;
+  d->m_stringList = value;
+}
+
+MP4::Item::Item(const MP4::CoverArtList &value)
+{
+  d = new ItemPrivate;
+  d->m_coverArtList = value;
+}
+
+bool
+MP4::Item::toBool() const
+{
+  return d->m_bool;
+}
+
+int
+MP4::Item::toInt() const
+{
+  return d->m_int;
+}
+
+MP4::Item::IntPair
+MP4::Item::toIntPair() const
+{
+  return d->m_intPair;
+}
+
+StringList
+MP4::Item::toStringList() const
+{
+  return d->m_stringList;
+}
+
+MP4::CoverArtList
+MP4::Item::toCoverArtList() const
+{
+  return d->m_coverArtList;
+}
+
+bool
+MP4::Item::isValid() const
+{
+  return d->valid;
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4item.h b/src/taglib/mp4/mp4item.h
new file mode 100644 (file)
index 0000000..50a025f
--- /dev/null
@@ -0,0 +1,72 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MP4ITEM_H
+#define TAGLIB_MP4ITEM_H
+
+#include "tstringlist.h"
+#include "mp4coverart.h"
+#include "taglib_export.h"
+
+namespace TagLib {
+
+  namespace MP4 {
+
+    class TAGLIB_EXPORT Item
+    {
+    public:
+      struct IntPair {
+        int first, second;
+      };
+
+      Item();
+      Item(const Item &item);
+      Item &operator=(const Item &item);
+      ~Item();
+
+      Item(int value);
+      Item(bool value);
+      Item(int first, int second);
+      Item(const StringList &value);
+      Item(const CoverArtList &value);
+
+      int toInt() const;
+      bool toBool() const;
+      IntPair toIntPair() const;
+      StringList toStringList() const;
+      CoverArtList toCoverArtList() const;
+
+      bool isValid() const;
+
+    private:
+      class ItemPrivate;
+      ItemPrivate *d;
+    };
+
+  }
+
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4properties.cpp b/src/taglib/mp4/mp4properties.cpp
new file mode 100644 (file)
index 0000000..c973d3a
--- /dev/null
@@ -0,0 +1,169 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_MP4
+
+#include <tdebug.h>
+#include <tstring.h>
+#include "mp4file.h"
+#include "mp4atom.h"
+#include "mp4properties.h"
+
+using namespace TagLib;
+
+class MP4::Properties::PropertiesPrivate
+{
+public:
+  PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0) {}
+
+  int length;
+  int bitrate;
+  int sampleRate;
+  int channels;
+  int bitsPerSample;
+};
+
+MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
+  : AudioProperties(style)
+{
+  d = new PropertiesPrivate;
+
+  MP4::Atom *moov = atoms->find("moov");
+  if(!moov) {
+    debug("MP4: Atom 'moov' not found");
+    return;
+  }
+
+  MP4::Atom *trak = 0;
+  ByteVector data;
+
+  MP4::AtomList trakList = moov->findall("trak");
+  for (unsigned int i = 0; i < trakList.size(); i++) {
+    trak = trakList[i];
+    MP4::Atom *hdlr = trak->find("mdia", "hdlr");
+    if(!hdlr) {
+      debug("MP4: Atom 'trak.mdia.hdlr' not found");
+      return;
+    }
+    file->seek(hdlr->offset);
+    data = file->readBlock(hdlr->length);
+    if(data.mid(16, 4) == "soun") {
+      break;
+    }
+    trak = 0;
+  }
+  if (!trak) {
+    debug("MP4: No audio tracks");
+    return;
+  }
+
+  MP4::Atom *mdhd = trak->find("mdia", "mdhd");
+  if(!mdhd) {
+    debug("MP4: Atom 'trak.mdia.mdhd' not found");
+    return;
+  }
+
+  file->seek(mdhd->offset);
+  data = file->readBlock(mdhd->length);
+  if(data[8] == 0) {
+    unsigned int unit = data.mid(20, 4).toUInt();
+    unsigned int length = data.mid(24, 4).toUInt();
+    d->length = length / unit;
+  }
+  else {
+    long long unit = data.mid(28, 8).toLongLong();
+    long long length = data.mid(36, 8).toLongLong();
+    d->length = int(length / unit);
+  }
+
+  MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
+  if(!atom) {
+    return;
+  }
+
+  file->seek(atom->offset);
+  data = file->readBlock(atom->length);
+  if(data.mid(20, 4) == "mp4a") {
+    d->channels = data.mid(40, 2).toShort();
+    d->bitsPerSample = data.mid(42, 2).toShort();
+    d->sampleRate = data.mid(46, 4).toUInt();
+    if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
+      long pos = 65;
+      if(data.mid(pos, 3) == "\x80\x80\x80") {
+        pos += 3;
+      }
+      pos += 4;
+      if(data[pos] == 0x04) {
+        pos += 1;
+        if(data.mid(pos, 3) == "\x80\x80\x80") {
+          pos += 3;
+        }
+        pos += 10;
+        d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000;
+      }
+    }
+  }
+}
+
+MP4::Properties::~Properties()
+{
+  delete d;
+}
+
+int
+MP4::Properties::channels() const
+{
+  return d->channels;
+}
+
+int
+MP4::Properties::sampleRate() const
+{
+  return d->sampleRate;
+}
+
+int
+MP4::Properties::length() const
+{
+  return d->length;
+}
+
+int
+MP4::Properties::bitrate() const
+{
+  return d->bitrate;
+}
+
+int
+MP4::Properties::bitsPerSample() const
+{
+  return d->bitsPerSample;
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4properties.h b/src/taglib/mp4/mp4properties.h
new file mode 100644 (file)
index 0000000..fb76c8a
--- /dev/null
@@ -0,0 +1,61 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MP4PROPERTIES_H
+#define TAGLIB_MP4PROPERTIES_H
+
+#include "taglib_export.h"
+#include "audioproperties.h"
+
+namespace TagLib {
+
+  namespace MP4 {
+
+    class Atoms;
+    class File;
+
+    //! An implementation of MP4 audio properties
+    class TAGLIB_EXPORT Properties : public AudioProperties
+    {
+    public:
+      Properties(File *file, Atoms *atoms, ReadStyle style = Average);
+      virtual ~Properties();
+
+      virtual int length() const;
+      virtual int bitrate() const;
+      virtual int sampleRate() const;
+      virtual int channels() const;
+      virtual int bitsPerSample() const;
+
+    private:
+      class PropertiesPrivate;
+      PropertiesPrivate *d;
+    };
+
+  }
+
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4tag.cpp b/src/taglib/mp4/mp4tag.cpp
new file mode 100644 (file)
index 0000000..f8acc87
--- /dev/null
@@ -0,0 +1,636 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_MP4
+
+#include <tdebug.h>
+#include <tstring.h>
+#include "mp4atom.h"
+#include "mp4tag.h"
+#include "id3v1genres.h"
+
+using namespace TagLib;
+
+class MP4::Tag::TagPrivate
+{
+public:
+  TagPrivate() : file(0), atoms(0) {}
+  ~TagPrivate() {}
+  TagLib::File *file;
+  Atoms *atoms;
+  ItemListMap items;
+};
+
+MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms)
+{
+  d = new TagPrivate;
+  d->file = file;
+  d->atoms = atoms;
+
+  MP4::Atom *ilst = atoms->find("moov", "udta", "meta", "ilst");
+  if(!ilst) {
+    //debug("Atom moov.udta.meta.ilst not found.");
+    return;
+  }
+
+  for(unsigned int i = 0; i < ilst->children.size(); i++) {
+    MP4::Atom *atom = ilst->children[i];
+    file->seek(atom->offset + 8);
+    if(atom->name == "----") {
+      parseFreeForm(atom, file);
+    }
+    else if(atom->name == "trkn" || atom->name == "disk") {
+      parseIntPair(atom, file);
+    }
+    else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst") {
+      parseBool(atom, file);
+    }
+    else if(atom->name == "tmpo") {
+      parseInt(atom, file);
+    }
+    else if(atom->name == "gnre") {
+      parseGnre(atom, file);
+    }
+    else if(atom->name == "covr") {
+      parseCovr(atom, file);
+    }
+    else {
+      parseText(atom, file);
+    }
+  }
+}
+
+MP4::Tag::~Tag()
+{
+  delete d;
+}
+
+ByteVectorList
+MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm)
+{
+  ByteVectorList result;
+  ByteVector data = file->readBlock(atom->length - 8);
+  int i = 0;
+  unsigned int pos = 0;
+  while(pos < data.size()) {
+    int length = data.mid(pos, 4).toUInt();
+    ByteVector name = data.mid(pos + 4, 4);
+    int flags = data.mid(pos + 8, 4).toUInt();
+    if(freeForm && i < 2) {
+      if(i == 0 && name != "mean") {
+        debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\"");
+        return result;
+      }
+      else if(i == 1 && name != "name") {
+        debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\"");
+        return result;
+      }
+      result.append(data.mid(pos + 12, length - 12));
+    }
+    else {
+      if(name != "data") {
+        debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
+        return result;
+      }
+      if(expectedFlags == -1 || flags == expectedFlags) {
+        result.append(data.mid(pos + 16, length - 16));
+      }
+    }
+    pos += length;
+    i++;
+  }
+  return result;
+}
+
+void
+MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file)
+{
+  ByteVectorList data = parseData(atom, file);
+  if(data.size()) {
+    d->items.insert(atom->name, (int)data[0].toShort());
+  }
+}
+
+void
+MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file)
+{
+  ByteVectorList data = parseData(atom, file);
+  if(data.size()) {
+    int idx = (int)data[0].toShort();
+    if(!d->items.contains("\251gen") && idx > 0) {
+      d->items.insert("\251gen", StringList(ID3v1::genre(idx - 1)));
+    }
+  }
+}
+
+void
+MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file)
+{
+  ByteVectorList data = parseData(atom, file);
+  if(data.size()) {
+    int a = data[0].mid(2, 2).toShort();
+    int b = data[0].mid(4, 2).toShort();
+    d->items.insert(atom->name, MP4::Item(a, b));
+  }
+}
+
+void
+MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file)
+{
+  ByteVectorList data = parseData(atom, file);
+  if(data.size()) {
+    bool value = data[0].size() ? data[0][0] != '\0' : false;
+    d->items.insert(atom->name, value);
+  }
+}
+
+void
+MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags)
+{
+  ByteVectorList data = parseData(atom, file, expectedFlags);
+  if(data.size()) {
+    StringList value;
+    for(unsigned int i = 0; i < data.size(); i++) {
+      value.append(String(data[i], String::UTF8));
+    }
+    d->items.insert(atom->name, value);
+  }
+}
+
+void
+MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file)
+{
+  ByteVectorList data = parseData(atom, file, 1, true);
+  if(data.size() > 2) {
+    StringList value;
+    for(unsigned int i = 2; i < data.size(); i++) {
+      value.append(String(data[i], String::UTF8));
+    }
+    String name = "----:" + data[0] + ':' + data[1];
+    d->items.insert(name, value);
+  }
+}
+
+void
+MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file)
+{
+  MP4::CoverArtList value;
+  ByteVector data = file->readBlock(atom->length - 8);
+  unsigned int pos = 0;
+  while(pos < data.size()) {
+    int length = data.mid(pos, 4).toUInt();
+    ByteVector name = data.mid(pos + 4, 4);
+    int flags = data.mid(pos + 8, 4).toUInt();
+    if(name != "data") {
+      debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
+      break;
+    }
+    if(flags == MP4::CoverArt::PNG || flags == MP4::CoverArt::JPEG) {
+      value.append(MP4::CoverArt(MP4::CoverArt::Format(flags),
+                                 data.mid(pos + 16, length - 16)));
+    }
+    pos += length;
+  }
+  if(value.size() > 0)
+    d->items.insert(atom->name, value);
+}
+
+ByteVector
+MP4::Tag::padIlst(const ByteVector &data, int length)
+{
+  if (length == -1) {
+    length = ((data.size() + 1023) & ~1023) - data.size();
+  }
+  return renderAtom("free", ByteVector(length, '\1'));
+}
+
+ByteVector
+MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data)
+{
+  return ByteVector::fromUInt(data.size() + 8) + name + data;
+}
+
+ByteVector
+MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data)
+{
+  ByteVector result;
+  for(unsigned int i = 0; i < data.size(); i++) {
+    result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + data[i]));
+  }
+  return renderAtom(name, result);
+}
+
+ByteVector
+MP4::Tag::renderBool(const ByteVector &name, MP4::Item &item)
+{
+  ByteVectorList data;
+  data.append(ByteVector(1, item.toBool() ? '\1' : '\0'));
+  return renderData(name, 0x15, data);
+}
+
+ByteVector
+MP4::Tag::renderInt(const ByteVector &name, MP4::Item &item)
+{
+  ByteVectorList data;
+  data.append(ByteVector::fromShort(item.toInt()));
+  return renderData(name, 0x15, data);
+}
+
+ByteVector
+MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item)
+{
+  ByteVectorList data;
+  data.append(ByteVector(2, '\0') +
+              ByteVector::fromShort(item.toIntPair().first) +
+              ByteVector::fromShort(item.toIntPair().second) +
+              ByteVector(2, '\0'));
+  return renderData(name, 0x00, data);
+}
+
+ByteVector
+MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, MP4::Item &item)
+{
+  ByteVectorList data;
+  data.append(ByteVector(2, '\0') +
+              ByteVector::fromShort(item.toIntPair().first) +
+              ByteVector::fromShort(item.toIntPair().second));
+  return renderData(name, 0x00, data);
+}
+
+ByteVector
+MP4::Tag::renderText(const ByteVector &name, MP4::Item &item, int flags)
+{
+  ByteVectorList data;
+  StringList value = item.toStringList();
+  for(unsigned int i = 0; i < value.size(); i++) {
+    data.append(value[i].data(String::UTF8));
+  }
+  return renderData(name, flags, data);
+}
+
+ByteVector
+MP4::Tag::renderCovr(const ByteVector &name, MP4::Item &item)
+{
+  ByteVector data;
+  MP4::CoverArtList value = item.toCoverArtList();
+  for(unsigned int i = 0; i < value.size(); i++) {
+    data.append(renderAtom("data", ByteVector::fromUInt(value[i].format()) +
+                                   ByteVector(4, '\0') + value[i].data()));
+  }
+  return renderAtom(name, data);
+}
+
+ByteVector
+MP4::Tag::renderFreeForm(const String &name, MP4::Item &item)
+{
+  StringList header = StringList::split(name, ":");
+  if (header.size() != 3) {
+    debug("MP4: Invalid free-form item name \"" + name + "\"");
+    return ByteVector::null;
+  }
+  ByteVector data;
+  data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8)));
+  data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8)));
+  StringList value = item.toStringList();
+  for(unsigned int i = 0; i < value.size(); i++) {
+    data.append(renderAtom("data", ByteVector::fromUInt(1) + ByteVector(4, '\0') + value[i].data(String::UTF8)));
+  }
+  return renderAtom("----", data);
+}
+
+bool
+MP4::Tag::save()
+{
+  ByteVector data;
+  for(MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) {
+    const String name = i->first;
+    if(name.startsWith("----")) {
+      data.append(renderFreeForm(name, i->second));
+    }
+    else if(name == "trkn") {
+      data.append(renderIntPair(name.data(String::Latin1), i->second));
+    }
+    else if(name == "disk") {
+      data.append(renderIntPairNoTrailing(name.data(String::Latin1), i->second));
+    }
+    else if(name == "cpil" || name == "pgap" || name == "pcst") {
+      data.append(renderBool(name.data(String::Latin1), i->second));
+    }
+    else if(name == "tmpo") {
+      data.append(renderInt(name.data(String::Latin1), i->second));
+    }
+    else if(name == "covr") {
+      data.append(renderCovr(name.data(String::Latin1), i->second));
+    }
+    else if(name.size() == 4){
+      data.append(renderText(name.data(String::Latin1), i->second));
+    }
+    else {
+      debug("MP4: Unknown item name \"" + name + "\"");
+    }
+  }
+  data = renderAtom("ilst", data);
+
+  AtomList path = d->atoms->path("moov", "udta", "meta", "ilst");
+  if(path.size() == 4) {
+    saveExisting(data, path);
+  }
+  else {
+    saveNew(data);
+  }
+
+  return true;
+}
+
+void
+MP4::Tag::updateParents(AtomList &path, long delta, int ignore)
+{
+  for(unsigned int i = 0; i < path.size() - ignore; i++) {
+    d->file->seek(path[i]->offset);
+    long size = d->file->readBlock(4).toUInt();
+    // 64-bit
+    if (size == 1) {
+      d->file->seek(4, File::Current); // Skip name
+      long long longSize = d->file->readBlock(8).toLongLong();
+      // Seek the offset of the 64-bit size
+      d->file->seek(path[i]->offset + 8);
+      d->file->writeBlock(ByteVector::fromLongLong(longSize + delta));
+    }
+    // 32-bit
+    else {
+      d->file->seek(path[i]->offset);
+      d->file->writeBlock(ByteVector::fromUInt(size + delta));
+    }
+  }
+}
+
+void
+MP4::Tag::updateOffsets(long delta, long offset)
+{
+  MP4::Atom *moov = d->atoms->find("moov");
+  if(moov) {
+    MP4::AtomList stco = moov->findall("stco", true);
+    for(unsigned int i = 0; i < stco.size(); i++) {
+      MP4::Atom *atom = stco[i];
+      if(atom->offset > offset) {
+        atom->offset += delta;
+      }
+      d->file->seek(atom->offset + 12);
+      ByteVector data = d->file->readBlock(atom->length - 12);
+      unsigned int count = data.mid(0, 4).toUInt();
+      d->file->seek(atom->offset + 16);
+      int pos = 4;
+      while(count--) {
+        long o = data.mid(pos, 4).toUInt();
+        if(o > offset) {
+          o += delta;
+        }
+        d->file->writeBlock(ByteVector::fromUInt(o));
+        pos += 4;
+      }
+    }
+
+    MP4::AtomList co64 = moov->findall("co64", true);
+    for(unsigned int i = 0; i < co64.size(); i++) {
+      MP4::Atom *atom = co64[i];
+      if(atom->offset > offset) {
+        atom->offset += delta;
+      }
+      d->file->seek(atom->offset + 12);
+      ByteVector data = d->file->readBlock(atom->length - 12);
+      unsigned int count = data.mid(0, 4).toUInt();
+      d->file->seek(atom->offset + 16);
+      int pos = 4;
+      while(count--) {
+        long long o = data.mid(pos, 8).toLongLong();
+        if(o > offset) {
+          o += delta;
+        }
+        d->file->writeBlock(ByteVector::fromLongLong(o));
+        pos += 8;
+      }
+    }
+  }
+
+  MP4::Atom *moof = d->atoms->find("moof");
+  if(moof) {
+    MP4::AtomList tfhd = moof->findall("tfhd", true);
+    for(unsigned int i = 0; i < tfhd.size(); i++) {
+      MP4::Atom *atom = tfhd[i];
+      if(atom->offset > offset) {
+        atom->offset += delta;
+      }
+      d->file->seek(atom->offset + 9);
+      ByteVector data = d->file->readBlock(atom->offset - 9);
+      unsigned int flags = (ByteVector(1, '\0') + data.mid(0, 3)).toUInt();
+      if(flags & 1) {
+        long long o = data.mid(7, 8).toLongLong();
+        if(o > offset) {
+          o += delta;
+        }
+        d->file->seek(atom->offset + 16);
+        d->file->writeBlock(ByteVector::fromLongLong(o));
+      }
+    }
+  }
+}
+
+void
+MP4::Tag::saveNew(ByteVector &data)
+{
+  data = renderAtom("meta", TagLib::ByteVector(4, '\0') +
+                    renderAtom("hdlr", TagLib::ByteVector(8, '\0') + TagLib::ByteVector("mdirappl") + TagLib::ByteVector(9, '\0')) +
+                    data + padIlst(data));
+
+  AtomList path = d->atoms->path("moov", "udta");
+  if(path.size() != 2) {
+    path = d->atoms->path("moov");
+    data = renderAtom("udta", data);
+  }
+
+  long offset = path[path.size() - 1]->offset + 8;
+  d->file->insert(data, offset, 0);
+
+  updateParents(path, data.size());
+  updateOffsets(data.size(), offset);
+}
+
+void
+MP4::Tag::saveExisting(ByteVector &data, AtomList &path)
+{
+  MP4::Atom *ilst = path[path.size() - 1];
+  long offset = ilst->offset;
+  long length = ilst->length;
+
+  MP4::Atom *meta = path[path.size() - 2];
+  AtomList::Iterator index = meta->children.find(ilst);
+
+  // check if there is an atom before 'ilst', and possibly use it as padding
+  if(index != meta->children.begin()) {
+    AtomList::Iterator prevIndex = index;
+    prevIndex--;
+    MP4::Atom *prev = *prevIndex;
+    if(prev->name == "free") {
+      offset = prev->offset;
+      length += prev->length;
+    }
+  }
+  // check if there is an atom after 'ilst', and possibly use it as padding
+  AtomList::Iterator nextIndex = index;
+  nextIndex++;
+  if(nextIndex != meta->children.end()) {
+    MP4::Atom *next = *nextIndex;
+    if(next->name == "free") {
+      length += next->length;
+    }
+  }
+
+  long delta = data.size() - length;
+  if(delta > 0 || (delta < 0 && delta > -8)) {
+    data.append(padIlst(data));
+    delta = data.size() - length;
+  }
+  else if(delta < 0) {
+    data.append(padIlst(data, -delta - 8));
+    delta = 0;
+  }
+
+  d->file->insert(data, offset, length);
+
+  if(delta) {
+    updateParents(path, delta, 1);
+    updateOffsets(delta, offset);
+  }
+}
+
+String
+MP4::Tag::title() const
+{
+  if(d->items.contains("\251nam"))
+    return d->items["\251nam"].toStringList().toString(", ");
+  return String::null;
+}
+
+String
+MP4::Tag::artist() const
+{
+  if(d->items.contains("\251ART"))
+    return d->items["\251ART"].toStringList().toString(", ");
+  return String::null;
+}
+
+String
+MP4::Tag::album() const
+{
+  if(d->items.contains("\251alb"))
+    return d->items["\251alb"].toStringList().toString(", ");
+  return String::null;
+}
+
+String
+MP4::Tag::comment() const
+{
+  if(d->items.contains("\251cmt"))
+    return d->items["\251cmt"].toStringList().toString(", ");
+  return String::null;
+}
+
+String
+MP4::Tag::genre() const
+{
+  if(d->items.contains("\251gen"))
+    return d->items["\251gen"].toStringList().toString(", ");
+  return String::null;
+}
+
+unsigned int
+MP4::Tag::year() const
+{
+  if(d->items.contains("\251day"))
+    return d->items["\251day"].toStringList().toString().toInt();
+  return 0;
+}
+
+unsigned int
+MP4::Tag::track() const
+{
+  if(d->items.contains("trkn"))
+    return d->items["trkn"].toIntPair().first;
+  return 0;
+}
+
+void
+MP4::Tag::setTitle(const String &value)
+{
+  d->items["\251nam"] = StringList(value);
+}
+
+void
+MP4::Tag::setArtist(const String &value)
+{
+  d->items["\251ART"] = StringList(value);
+}
+
+void
+MP4::Tag::setAlbum(const String &value)
+{
+  d->items["\251alb"] = StringList(value);
+}
+
+void
+MP4::Tag::setComment(const String &value)
+{
+  d->items["\251cmt"] = StringList(value);
+}
+
+void
+MP4::Tag::setGenre(const String &value)
+{
+  d->items["\251gen"] = StringList(value);
+}
+
+void
+MP4::Tag::setYear(uint value)
+{
+  d->items["\251day"] = StringList(String::number(value));
+}
+
+void
+MP4::Tag::setTrack(uint value)
+{
+  d->items["trkn"] = MP4::Item(value, 0);
+}
+
+MP4::ItemListMap &
+MP4::Tag::itemListMap()
+{
+  return d->items;
+}
+
+#endif
diff --git a/src/taglib/mp4/mp4tag.h b/src/taglib/mp4/mp4tag.h
new file mode 100644 (file)
index 0000000..6d7f140
--- /dev/null
@@ -0,0 +1,104 @@
+/**************************************************************************
+    copyright            : (C) 2007 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+ **************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MP4TAG_H
+#define TAGLIB_MP4TAG_H
+
+#include "tag.h"
+#include "tbytevectorlist.h"
+#include "tfile.h"
+#include "tmap.h"
+#include "tstringlist.h"
+#include "taglib_export.h"
+#include "mp4atom.h"
+#include "mp4item.h"
+
+namespace TagLib {
+
+  namespace MP4 {
+
+    typedef TagLib::Map<String, Item> ItemListMap;
+
+    class TAGLIB_EXPORT Tag: public TagLib::Tag
+    {
+    public:
+        Tag(TagLib::File *file, Atoms *atoms);
+        ~Tag();
+        bool save();
+
+        String title() const;
+        String artist() const;
+        String album() const;
+        String comment() const;
+        String genre() const;
+        uint year() const;
+        uint track() const;
+
+        void setTitle(const String &value);
+        void setArtist(const String &value);
+        void setAlbum(const String &value);
+        void setComment(const String &value);
+        void setGenre(const String &value);
+        void setYear(uint value);
+        void setTrack(uint value);
+
+        ItemListMap &itemListMap();
+
+    private:
+        TagLib::ByteVectorList parseData(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false);
+        void parseText(Atom *atom, TagLib::File *file, int expectedFlags = 1);
+        void parseFreeForm(Atom *atom, TagLib::File *file);
+        void parseInt(Atom *atom, TagLib::File *file);
+        void parseGnre(Atom *atom, TagLib::File *file);
+        void parseIntPair(Atom *atom, TagLib::File *file);
+        void parseBool(Atom *atom, TagLib::File *file);
+        void parseCovr(Atom *atom, TagLib::File *file);
+
+        TagLib::ByteVector padIlst(const ByteVector &data, int length = -1);
+        TagLib::ByteVector renderAtom(const ByteVector &name, const TagLib::ByteVector &data);
+        TagLib::ByteVector renderData(const ByteVector &name, int flags, const TagLib::ByteVectorList &data);
+        TagLib::ByteVector renderText(const ByteVector &name, Item &item, int flags = 1);
+        TagLib::ByteVector renderFreeForm(const String &name, Item &item);
+        TagLib::ByteVector renderBool(const ByteVector &name, Item &item);
+        TagLib::ByteVector renderInt(const ByteVector &name, Item &item);
+        TagLib::ByteVector renderIntPair(const ByteVector &name, Item &item);
+        TagLib::ByteVector renderIntPairNoTrailing(const ByteVector &name, Item &item);
+        TagLib::ByteVector renderCovr(const ByteVector &name, Item &item);
+
+        void updateParents(AtomList &path, long delta, int ignore = 0);
+        void updateOffsets(long delta, long offset);
+
+        void saveNew(TagLib::ByteVector &data);
+        void saveExisting(TagLib::ByteVector &data, AtomList &path);
+
+        class TagPrivate;
+        TagPrivate *d;
+    };
+
+  }
+
+}
+
+#endif
diff --git a/src/taglib/mpc/mpcfile.cpp b/src/taglib/mpc/mpcfile.cpp
new file mode 100644 (file)
index 0000000..922bf83
--- /dev/null
@@ -0,0 +1,325 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <tbytevector.h>
+#include <tstring.h>
+#include <tagunion.h>
+#include <tdebug.h>
+
+#include "mpcfile.h"
+#include "id3v1tag.h"
+#include "id3v2header.h"
+#include "apetag.h"
+#include "apefooter.h"
+
+using namespace TagLib;
+
+namespace
+{
+  enum { APEIndex, ID3v1Index };
+}
+
+class MPC::File::FilePrivate
+{
+public:
+  FilePrivate() :
+    APELocation(-1),
+    APESize(0),
+    ID3v1Location(-1),
+    ID3v2Header(0),
+    ID3v2Location(-1),
+    ID3v2Size(0),
+    properties(0),
+    scanned(false),
+    hasAPE(false),
+    hasID3v1(false),
+    hasID3v2(false) {}
+
+  ~FilePrivate()
+  {
+    delete ID3v2Header;
+    delete properties;
+  }
+
+  long APELocation;
+  uint APESize;
+
+  long ID3v1Location;
+
+  ID3v2::Header *ID3v2Header;
+  long ID3v2Location;
+  uint ID3v2Size;
+
+  TagUnion tag;
+
+  Properties *properties;
+  bool scanned;
+
+  // These indicate whether the file *on disk* has these tags, not if
+  // this data structure does.  This is used in computing offsets.
+
+  bool hasAPE;
+  bool hasID3v1;
+  bool hasID3v2;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+MPC::File::File(FileName file, bool readProperties,
+                Properties::ReadStyle propertiesStyle) : TagLib::File(file)
+{
+  d = new FilePrivate;
+  read(readProperties, propertiesStyle);
+}
+
+MPC::File::~File()
+{
+  delete d;
+}
+
+TagLib::Tag *MPC::File::tag() const
+{
+  return &d->tag;
+}
+
+MPC::Properties *MPC::File::audioProperties() const
+{
+  return d->properties;
+}
+
+bool MPC::File::save()
+{
+  if(readOnly()) {
+    debug("MPC::File::save() -- File is read only.");
+    return false;
+  }
+
+  // Possibly strip ID3v2 tag
+
+  if(d->hasID3v2 && !d->ID3v2Header) {
+    removeBlock(d->ID3v2Location, d->ID3v2Size);
+    d->hasID3v2 = false;
+    if(d->hasID3v1)
+      d->ID3v1Location -= d->ID3v2Size;
+    if(d->hasAPE)
+      d->APELocation -= d->ID3v2Size;
+  }
+
+  // Update ID3v1 tag
+
+  if(ID3v1Tag()) {
+    if(d->hasID3v1) {
+      seek(d->ID3v1Location);
+      writeBlock(ID3v1Tag()->render());
+    }
+    else {
+      seek(0, End);
+      d->ID3v1Location = tell();
+      writeBlock(ID3v1Tag()->render());
+      d->hasID3v1 = true;
+    }
+  } else
+    if(d->hasID3v1) {
+      removeBlock(d->ID3v1Location, 128);
+      d->hasID3v1 = false;
+      if(d->hasAPE) {
+        if(d->APELocation > d->ID3v1Location)
+          d->APELocation -= 128;
+      }
+    }
+
+  // Update APE tag
+
+  if(APETag()) {
+    if(d->hasAPE)
+      insert(APETag()->render(), d->APELocation, d->APESize);
+    else {
+      if(d->hasID3v1)  {
+        insert(APETag()->render(), d->ID3v1Location, 0);
+        d->APESize = APETag()->footer()->completeTagSize();
+        d->hasAPE = true;
+        d->APELocation = d->ID3v1Location;
+        d->ID3v1Location += d->APESize;
+      }
+      else {
+        seek(0, End);
+        d->APELocation = tell();
+        writeBlock(APETag()->render());
+        d->APESize = APETag()->footer()->completeTagSize();
+        d->hasAPE = true;
+      }
+    }
+  }
+  else
+    if(d->hasAPE) {
+      removeBlock(d->APELocation, d->APESize);
+      d->hasAPE = false;
+      if(d->hasID3v1) {
+        if(d->ID3v1Location > d->APELocation)
+          d->ID3v1Location -= d->APESize;
+      }
+    }
+
+  return true;
+}
+
+ID3v1::Tag *MPC::File::ID3v1Tag(bool create)
+{
+  return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
+}
+
+APE::Tag *MPC::File::APETag(bool create)
+{
+  return d->tag.access<APE::Tag>(APEIndex, create);
+}
+
+void MPC::File::strip(int tags)
+{
+  if(tags & ID3v1) {
+    d->tag.set(ID3v1Index, 0);
+    APETag(true);
+  }
+
+  if(tags & ID3v2) {
+    delete d->ID3v2Header;
+    d->ID3v2Header = 0;
+  }
+
+  if(tags & APE) {
+    d->tag.set(APEIndex, 0);
+
+    if(!ID3v1Tag())
+      APETag(true);
+  }
+}
+
+void MPC::File::remove(int tags)
+{
+  strip(tags);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
+{
+  // Look for an ID3v1 tag
+
+  d->ID3v1Location = findID3v1();
+
+  if(d->ID3v1Location >= 0) {
+    d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
+    d->hasID3v1 = true;
+  }
+
+  // Look for an APE tag
+
+  findAPE();
+
+  d->APELocation = findAPE();
+
+  if(d->APELocation >= 0) {
+    d->tag.set(APEIndex, new APE::Tag(this, d->APELocation));
+
+    d->APESize = APETag()->footer()->completeTagSize();
+    d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
+    d->hasAPE = true;
+  }
+
+  if(!d->hasID3v1)
+    APETag(true);
+
+  // Look for and skip an ID3v2 tag
+
+  d->ID3v2Location = findID3v2();
+
+  if(d->ID3v2Location >= 0) {
+    seek(d->ID3v2Location);
+    d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
+    d->ID3v2Size = d->ID3v2Header->completeTagSize();
+    d->hasID3v2 = true;
+  }
+
+  if(d->hasID3v2)
+    seek(d->ID3v2Location + d->ID3v2Size);
+  else
+    seek(0);
+
+  // Look for MPC metadata
+
+  if(readProperties) {
+    d->properties = new Properties(readBlock(MPC::HeaderSize),
+                                   length() - d->ID3v2Size - d->APESize);
+  }
+}
+
+long MPC::File::findAPE()
+{
+  if(!isValid())
+    return -1;
+
+  if(d->hasID3v1)
+    seek(-160, End);
+  else
+    seek(-32, End);
+
+  long p = tell();
+
+  if(readBlock(8) == APE::Tag::fileIdentifier())
+    return p;
+
+  return -1;
+}
+
+long MPC::File::findID3v1()
+{
+  if(!isValid())
+    return -1;
+
+  seek(-128, End);
+  long p = tell();
+
+  if(readBlock(3) == ID3v1::Tag::fileIdentifier())
+    return p;
+
+  return -1;
+}
+
+long MPC::File::findID3v2()
+{
+  if(!isValid())
+    return -1;
+
+  seek(0);
+
+  if(readBlock(3) == ID3v2::Header::fileIdentifier())
+    return 0;
+
+  return -1;
+}
diff --git a/src/taglib/mpc/mpcfile.h b/src/taglib/mpc/mpcfile.h
new file mode 100644 (file)
index 0000000..7e34c86
--- /dev/null
@@ -0,0 +1,175 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MPCFILE_H
+#define TAGLIB_MPCFILE_H
+
+#include "taglib_export.h"
+#include "tfile.h"
+
+#include "mpcproperties.h"
+
+namespace TagLib {
+
+  class Tag;
+
+  namespace ID3v1 { class Tag; }
+  namespace APE { class Tag; }
+
+  //! An implementation of MPC metadata
+
+  /*!
+   * This is implementation of MPC metadata.
+   *
+   * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream
+   * properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped
+   * and ignored.
+   */
+
+  namespace MPC {
+
+    //! An implementation of TagLib::File with MPC specific methods
+
+    /*!
+     * This implements and provides an interface for MPC files to the
+     * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
+     * the abstract TagLib::File API as well as providing some additional
+     * information specific to MPC files.
+     * The only invalid tag combination supported is an ID3v1 tag after an APE tag.
+     */
+
+    class TAGLIB_EXPORT File : public TagLib::File
+    {
+    public:
+      /*!
+       * This set of flags is used for various operations and is suitable for
+       * being OR-ed together.
+       */
+      enum TagTypes {
+        //! Empty set.  Matches no tag types.
+        NoTags  = 0x0000,
+        //! Matches ID3v1 tags.
+        ID3v1   = 0x0001,
+        //! Matches ID3v2 tags.
+        ID3v2   = 0x0002,
+        //! Matches APE tags.
+        APE     = 0x0004,
+        //! Matches all tag types.
+        AllTags = 0xffff
+      };
+
+      /*!
+       * Contructs an MPC file from \a file.  If \a readProperties is true the
+       * file's audio properties will also be read using \a propertiesStyle.  If
+       * false, \a propertiesStyle is ignored.
+       */
+      File(FileName file, bool readProperties = true,
+           Properties::ReadStyle propertiesStyle = Properties::Average);
+
+      /*!
+       * Destroys this instance of the File.
+       */
+      virtual ~File();
+
+      /*!
+       * Returns the Tag for this file.  This will be an APE tag, an ID3v1 tag
+       * or a combination of the two.
+       */
+      virtual TagLib::Tag *tag() const;
+
+      /*!
+       * Returns the MPC::Properties for this file.  If no audio properties
+       * were read then this will return a null pointer.
+       */
+      virtual Properties *audioProperties() const;
+
+      /*!
+       * Saves the file.
+       */
+      virtual bool save();
+
+      /*!
+       * Returns a pointer to the ID3v1 tag of the file.
+       *
+       * If \a create is false (the default) this will return a null pointer
+       * if there is no valid ID3v1 tag.  If \a create is true it will create
+       * an ID3v1 tag if one does not exist. If there is already an APE tag, the
+       * new ID3v1 tag will be placed after it.
+       *
+       * \note The Tag <b>is still</b> owned by the APE::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      ID3v1::Tag *ID3v1Tag(bool create = false);
+
+      /*!
+       * Returns a pointer to the APE tag of the file.
+       *
+       * If \a create is false (the default) this will return a null pointer
+       * if there is no valid APE tag.  If \a create is true it will create
+       * a APE tag if one does not exist. If there is already an ID3v1 tag, thes
+       * new APE tag will be placed before it.
+       *
+       * \note The Tag <b>is still</b> owned by the APE::File and should not be
+       * deleted by the user.  It will be deleted when the file (object) is
+       * destroyed.
+       */
+      APE::Tag *APETag(bool create = false);
+
+      /*!
+       * This will remove the tags that match the OR-ed together TagTypes from the
+       * file.  By default it removes all tags.
+       *
+       * \warning This will also invalidate pointers to the tags
+       * as their memory will be freed.
+       *
+       * \note In order to make the removal permanent save() still needs to be called.
+       */
+      void strip(int tags = AllTags);
+
+      /*!
+       * \deprecated
+       * \see strip
+       */
+      void remove(int tags = AllTags);
+
+
+    private:
+      File(const File &);
+      File &operator=(const File &);
+
+      void read(bool readProperties, Properties::ReadStyle propertiesStyle);
+      void scan();
+      long findAPE();
+      long findID3v1();
+      long findID3v2();
+
+      class FilePrivate;
+      FilePrivate *d;
+    };
+  }
+}
+
+#endif
diff --git a/src/taglib/mpc/mpcproperties.cpp b/src/taglib/mpc/mpcproperties.cpp
new file mode 100644 (file)
index 0000000..2114a86
--- /dev/null
@@ -0,0 +1,140 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <tstring.h>
+#include <tdebug.h>
+#include <bitset>
+
+#include "mpcproperties.h"
+#include "mpcfile.h"
+
+using namespace TagLib;
+
+class MPC::Properties::PropertiesPrivate
+{
+public:
+  PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) :
+    data(d),
+    streamLength(length),
+    style(s),
+    version(0),
+    length(0),
+    bitrate(0),
+    sampleRate(0),
+    channels(0) {}
+
+  ByteVector data;
+  long streamLength;
+  ReadStyle style;
+  int version;
+  int length;
+  int bitrate;
+  int sampleRate;
+  int channels;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style)
+{
+  d = new PropertiesPrivate(data, streamLength, style);
+  read();
+}
+
+MPC::Properties::~Properties()
+{
+  delete d;
+}
+
+int MPC::Properties::length() const
+{
+  return d->length;
+}
+
+int MPC::Properties::bitrate() const
+{
+  return d->bitrate;
+}
+
+int MPC::Properties::sampleRate() const
+{
+  return d->sampleRate;
+}
+
+int MPC::Properties::channels() const
+{
+  return d->channels;
+}
+
+int MPC::Properties::mpcVersion() const
+{
+  return d->version;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 };
+
+void MPC::Properties::read()
+{
+  if(!d->data.startsWith("MP+"))
+    return;
+
+  d->version = d->data[3] & 15;
+
+  unsigned int frames;
+
+  if(d->version >= 7) {
+    frames = d->data.mid(4, 4).toUInt(false);
+
+    std::bitset<32> flags = d->data.mid(8, 4).toUInt(false);
+    d->sampleRate = sftable[flags[17] * 2 + flags[16]];
+    d->channels = 2;
+  }
+  else {
+    uint headerData = d->data.mid(0, 4).toUInt(false);
+
+    d->bitrate = (headerData >> 23) & 0x01ff;
+    d->version = (headerData >> 11) & 0x03ff;
+    d->sampleRate = 44100;
+    d->channels = 2;
+
+    if(d->version >= 5)
+      frames = d->data.mid(4, 4).toUInt(false);
+    else
+      frames = d->data.mid(6, 2).toUInt(false);
+  }
+
+  uint samples = frames * 1152 - 576;
+
+  d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0;
+
+  if(!d->bitrate)
+    d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
+}
diff --git a/src/taglib/mpc/mpcproperties.h b/src/taglib/mpc/mpcproperties.h
new file mode 100644 (file)
index 0000000..bdbc887
--- /dev/null
@@ -0,0 +1,85 @@
+/***************************************************************************
+    copyright            : (C) 2004 by Allan Sandfeld Jensen
+    email                : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_MPCPROPERTIES_H
+#define TAGLIB_MPCPROPERTIES_H
+
+#include "taglib_export.h"
+#include "audioproperties.h"
+
+namespace TagLib {
+
+  namespace MPC {
+
+    class File;
+
+    static const uint HeaderSize = 8*7;
+
+    //! An implementation of audio property reading for MPC
+
+    /*!
+     * This reads the data from an MPC stream found in the AudioProperties
+     * API.
+     */
+
+    class TAGLIB_EXPORT Properties : public AudioProperties
+    {
+    public:
+      /*!
+       * Create an instance of MPC::Properties with the data read from the
+       * ByteVector \a data.
+       */
+      Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
+
+      /*!
+       * Destroys this MPC::Properties instance.
+       */
+      virtual ~Properties();
+
+      // Reimplementations.
+
+      virtual int length() const;
+      virtual int bitrate() const;
+      virtual int sampleRate() const;
+      virtual int channels() const;
+
+      /*!
+       * Returns the version of the bitstream (SV4-SV7)
+       */
+      int mpcVersion() const;
+
+    private:
+      Properties(const Properties &);
+      Properties &operator=(const Properties &);
+
+      void read();
+
+      class PropertiesPrivate;
+      PropertiesPrivate *d;
+    };
+  }
+}
+
+#endif
diff --git a/src/taglib/mpeg/id3v1/id3v1genres.cpp b/src/taglib/mpeg/id3v1/id3v1genres.cpp
new file mode 100644 (file)
index 0000000..7cd42f3
--- /dev/null
@@ -0,0 +1,219 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include "id3v1genres.h"
+
+using namespace TagLib;
+
+namespace TagLib {
+  namespace ID3v1 {
+
+    static const int genresSize = 148;
+    static const String genres[] = {
+      "Blues",
+      "Classic Rock",
+      "Country",
+      "Dance",
+      "Disco",
+      "Funk",
+      "Grunge",
+      "Hip-Hop",
+      "Jazz",
+      "Metal",
+      "New Age",
+      "Oldies",
+      "Other",
+      "Pop",
+      "R&B",
+      "Rap",
+      "Reggae",
+      "Rock",
+      "Techno",
+      "Industrial",
+      "Alternative",
+      "Ska",
+      "Death Metal",
+      "Pranks",
+      "Soundtrack",
+      "Euro-Techno",
+      "Ambient",
+      "Trip-Hop",
+      "Vocal",
+      "Jazz+Funk",
+      "Fusion",
+      "Trance",
+      "Classical",
+      "Instrumental",
+      "Acid",
+      "House",
+      "Game",
+      "Sound Clip",
+      "Gospel",
+      "Noise",
+      "Alternative Rock",
+      "Bass",
+      "Soul",
+      "Punk",
+      "Space",
+      "Meditative",
+      "Instrumental Pop",
+      "Instrumental Rock",
+      "Ethnic",
+      "Gothic",
+      "Darkwave",
+      "Techno-Industrial",
+      "Electronic",
+      "Pop-Folk",
+      "Eurodance",
+      "Dream",
+      "Southern Rock",
+      "Comedy",
+      "Cult",
+      "Gangsta",
+      "Top 40",
+      "Christian Rap",
+      "Pop/Funk",
+      "Jungle",
+      "Native American",
+      "Cabaret",
+      "New Wave",
+      "Psychedelic",
+      "Rave",
+      "Showtunes",
+      "Trailer",
+      "Lo-Fi",
+      "Tribal",
+      "Acid Punk",
+      "Acid Jazz",
+      "Polka",
+      "Retro",
+      "Musical",
+      "Rock & Roll",
+      "Hard Rock",
+      "Folk",
+      "Folk/Rock",
+      "National Folk",
+      "Swing",
+      "Fusion",
+      "Bebob",
+      "Latin",
+      "Revival",
+      "Celtic",
+      "Bluegrass",
+      "Avantgarde",
+      "Gothic Rock",
+      "Progressive Rock",
+      "Psychedelic Rock",
+      "Symphonic Rock",
+      "Slow Rock",
+      "Big Band",
+      "Chorus",
+      "Easy Listening",
+      "Acoustic",
+      "Humour",
+      "Speech",
+      "Chanson",
+      "Opera",
+      "Chamber Music",
+      "Sonata",
+      "Symphony",
+      "Booty Bass",
+      "Primus",
+      "Porn Groove",
+      "Satire",
+      "Slow Jam",
+      "Club",
+      "Tango",
+      "Samba",
+      "Folklore",
+      "Ballad",
+      "Power Ballad",
+      "Rhythmic Soul",
+      "Freestyle",
+      "Duet",
+      "Punk Rock",
+      "Drum Solo",
+      "A Cappella",
+      "Euro-House",
+      "Dance Hall",
+      "Goa",
+      "Drum & Bass",
+      "Club-House",
+      "Hardcore",
+      "Terror",
+      "Indie",
+      "BritPop",
+      "Negerpunk",
+      "Polsk Punk",
+      "Beat",
+      "Christian Gangsta Rap",
+      "Heavy Metal",
+      "Black Metal",
+      "Crossover",
+      "Contemporary Christian",
+      "Christian Rock",
+      "Merengue",
+      "Salsa",
+      "Thrash Metal",
+      "Anime",
+      "Jpop",
+      "Synthpop"
+    };
+  }
+}
+
+StringList ID3v1::genreList()
+{
+  static StringList l;
+  if(l.isEmpty()) {
+    for(int i = 0; i < genresSize; i++)
+      l.append(genres[i]);
+  }
+  return l;
+}
+
+ID3v1::GenreMap ID3v1::genreMap()
+{
+  static GenreMap m;
+  if(m.isEmpty()) {
+    for(int i = 0; i < genresSize; i++)
+      m.insert(genres[i], i);
+  }
+  return m;
+}
+
+String ID3v1::genre(int i)
+{
+  if(i >= 0 && i < genresSize)
+    return genres[i];
+  return String::null;
+}
+
+int ID3v1::genreIndex(const String &name)
+{
+  if(genreMap().contains(name))
+    return genreMap()[name];
+  return 255;
+}
diff --git a/src/taglib/mpeg/id3v1/id3v1genres.h b/src/taglib/mpeg/id3v1/id3v1genres.h
new file mode 100644 (file)
index 0000000..cb79056
--- /dev/null
@@ -0,0 +1,66 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_ID3V1GENRE_H
+#define TAGLIB_ID3V1GENRE_H
+
+#include "tmap.h"
+#include "tstringlist.h"
+#include "taglib_export.h"
+
+namespace TagLib {
+  namespace ID3v1 {
+
+    typedef Map<String, int> GenreMap;
+
+    /*!
+     * Returns the list of canonical ID3v1 genre names in the order that they
+     * are listed in the standard.
+     */
+    StringList TAGLIB_EXPORT genreList();
+
+    /*!
+     * A "reverse mapping" that goes from the canonical ID3v1 genre name to the
+     * respective genre number.   genreMap()["Rock"] ==
+     */
+    GenreMap TAGLIB_EXPORT genreMap();
+
+    /*!
+     * Returns the name of the genre at \a index in the ID3v1 genre list.  If
+     * \a index is out of range -- less than zero or greater than 146 -- a null
+     * string will be returned.
+     */
+    String TAGLIB_EXPORT genre(int index);
+
+    /*!
+     * Returns the genre index for the (case sensitive) genre \a name.  If the
+     * genre is not in the list 255 (which signifies an unknown genre in ID3v1)
+     * will be returned.
+     */
+    int TAGLIB_EXPORT genreIndex(const String &name);
+  }
+}
+
+#endif
diff --git a/src/taglib/mpeg/id3v1/id3v1tag.cpp b/src/taglib/mpeg/id3v1/id3v1tag.cpp
new file mode 100644 (file)
index 0000000..490f8dd
--- /dev/null
@@ -0,0 +1,248 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <tdebug.h>
+#include <tfile.h>
+
+#include "id3v1tag.h"
+#include "id3v1genres.h"
+
+using namespace TagLib;
+using namespace ID3v1;
+
+class ID3v1::Tag::TagPrivate
+{
+public:
+  TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {}
+
+  File *file;
+  long tagOffset;
+
+  String title;
+  String artist;
+  String album;
+  String year;
+  String comment;
+  uchar track;
+  uchar genre;
+
+  static const StringHandler *stringHandler;
+};
+
+const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = new StringHandler;
+
+////////////////////////////////////////////////////////////////////////////////
+// StringHandler implementation
+////////////////////////////////////////////////////////////////////////////////
+
+String ID3v1::StringHandler::parse(const ByteVector &data) const
+{
+  return String(data, String::Latin1).stripWhiteSpace();
+}
+
+ByteVector ID3v1::StringHandler::render(const String &s) const
+{
+  if(!s.isLatin1())
+  {
+    return ByteVector();
+  }
+
+  return s.data(String::Latin1);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public methods
+////////////////////////////////////////////////////////////////////////////////
+
+ID3v1::Tag::Tag() : TagLib::Tag()
+{
+  d = new TagPrivate;
+}
+
+ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag()
+{
+  d = new TagPrivate;
+  d->file = file;
+  d->tagOffset = tagOffset;
+
+  read();
+}
+
+ID3v1::Tag::~Tag()
+{
+  delete d;
+}
+
+ByteVector ID3v1::Tag::render() const
+{
+  ByteVector data;
+
+  data.append(fileIdentifier());
+  data.append(TagPrivate::stringHandler->render(d->title).resize(30));
+  data.append(TagPrivate::stringHandler->render(d->artist).resize(30));
+  data.append(TagPrivate::stringHandler->render(d->album).resize(30));
+  data.append(TagPrivate::stringHandler->render(d->year).resize(4));
+  data.append(TagPrivate::stringHandler->render(d->comment).resize(28));
+  data.append(char(0));
+  data.append(char(d->track));
+  data.append(char(d->genre));
+
+  return data;
+}
+
+ByteVector ID3v1::Tag::fileIdentifier()
+{
+  return ByteVector::fromCString("TAG");
+}
+
+String ID3v1::Tag::title() const
+{
+  return d->title;
+}
+
+String ID3v1::Tag::artist() const
+{
+  return d->artist;
+}
+
+String ID3v1::Tag::album() const
+{
+  return d->album;
+}
+
+String ID3v1::Tag::comment() const
+{
+  return d->comment;
+}
+
+String ID3v1::Tag::genre() const
+{
+  return ID3v1::genre(d->genre);
+}
+
+TagLib::uint ID3v1::Tag::year() const
+{
+  return d->year.toInt();
+}
+
+TagLib::uint ID3v1::Tag::track() const
+{
+  return d->track;
+}
+
+void ID3v1::Tag::setTitle(const String &s)
+{
+  d->title = s;
+}
+
+void ID3v1::Tag::setArtist(const String &s)
+{
+  d->artist = s;
+}
+
+void ID3v1::Tag::setAlbum(const String &s)
+{
+  d->album = s;
+}
+
+void ID3v1::Tag::setComment(const String &s)
+{
+  d->comment = s;
+}
+
+void ID3v1::Tag::setGenre(const String &s)
+{
+  d->genre = ID3v1::genreIndex(s);
+}
+
+void ID3v1::Tag::setYear(uint i)
+{
+  d->year = i > 0 ? String::number(i) : String::null;
+}
+
+void ID3v1::Tag::setTrack(uint i)
+{
+  d->track = i < 256 ? i : 0;
+}
+
+void ID3v1::Tag::setStringHandler(const StringHandler *handler)
+{
+  delete TagPrivate::stringHandler;
+  TagPrivate::stringHandler = handler;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected methods
+////////////////////////////////////////////////////////////////////////////////
+
+void ID3v1::Tag::read()
+{
+  if(d->file && d->file->isValid()) {
+    d->file->seek(d->tagOffset);
+    // read the tag -- always 128 bytes
+    ByteVector data = d->file->readBlock(128);
+
+    // some initial sanity checking
+    if(data.size() == 128 && data.startsWith("TAG"))
+      parse(data);
+    else
+      debug("ID3v1 tag is not valid or could not be read at the specified offset.");
+  }
+}
+
+void ID3v1::Tag::parse(const ByteVector &data)
+{
+  int offset = 3;
+
+  d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+  offset += 30;
+
+  d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+  offset += 30;
+
+  d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30));
+  offset += 30;
+
+  d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4));
+  offset += 4;
+
+  // Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this
+  // is not a bug in TagLib.  Since a zeroed byte is what we would expect to
+  // indicate the end of a C-String, specifically the comment string, a value of
+  // zero must be assumed to be just that.
+
+  if(data[offset + 28] == 0 && data[offset + 29] != 0) {
+    // ID3v1.1 detected
+
+    d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28));
+    d->track = uchar(data[offset + 29]);
+  }
+  else
+    d->comment = data.mid(offset, 30);
+
+  offset += 30;
+
+  d->genre = uchar(data[offset]);
+}
diff --git a/src/taglib/mpeg/id3v1/id3v1tag.h b/src/taglib/mpeg/id3v1/id3v1tag.h
new file mode 100644 (file)
index 0000000..629d589
--- /dev/null
@@ -0,0 +1,181 @@
+/***************************************************************************
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
+ *   USA                                                                   *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_ID3V1TAG_H
+#define TAGLIB_ID3V1TAG_H
+
+#include "tag.h"
+#include "tbytevector.h"
+#include "taglib_export.h"
+
+namespace TagLib {
+
+  class File;
+
+  //! An ID3v1 implementation
+
+  namespace ID3v1 {
+
+    //! A abstraction for the string to data encoding in ID3v1 tags.
+
+    /*!
+     * ID3v1 should in theory always contain ISO-8859-1 (Latin1) data.  In
+     * practice it does not.  TagLib by default only supports ISO-8859-1 data
+     * in ID3v1 tags.
+     *
+     * However by subclassing this class and reimplementing parse() and render()
+     * and setting your reimplementation as the default with
+     * ID3v1::Tag::setStringHandler() you can define how you would like these
+     * transformations to be done.
+     *
+     * \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1
+     * tags.  Please consider disabling the writing of ID3v1 tags in the case
+     * that the data is not ISO-8859-1.
+     *
+     * \see ID3v1::Tag::setStringHandler()
+     */
+
+    class TAGLIB_EXPORT StringHandler
+    {
+      TAGLIB_IGNORE_MISSING_DESTRUCTOR
+    public:
+      // BIC: Add virtual destructor.
+
+      /*!
+       * Decode a string from \a data.  The default implementation assumes that
+       * \a data is an ISO-8859-1 (Latin1) character array.
+       */
+      virtual String parse(const ByteVector &data) const;
+
+      /*!
+       * Encode a ByteVector with the data from \a s.  The default implementation
+       * assumes that \a s is an ISO-8859-1 (Latin1) string.  If the string is
+       * does not conform to ISO-8859-1, no value is written.
+       *
+       * \warning It is recommended that you <b>not</b> override this method, but
+       * instead do not write an ID3v1 tag in the case that the data is not
+       * ISO-8859-1.
+       */
+      virtual ByteVector render(const String &s) const;
+    };
+
+    //! The main class in the ID3v1 implementation
+
+    /*!
+     * This is an implementation of the ID3v1 format.  ID3v1 is both the simplist
+     * and most common of tag formats but is rather limited.  Because of its
+     * pervasiveness and the way that applications have been written around the
+     * fields that it provides, the generic TagLib::Tag API is a mirror of what is
+     * provided by ID3v1.
+     *
+     * ID3v1 tags should generally only contain Latin1 information.  However because
+     * many applications do not follow this rule there is now support for overriding
+     * the ID3v1 string handling using the ID3v1::StringHandler class.  Please see
+     * the documentation for that class for more information.
+     *
+     * \see StringHandler
+     *
+     * \note Most fields are truncated to a maximum of 28-30 bytes.  The
+     * truncation happens automatically when the tag is rendered.
+     */
+
+    class TAGLIB_EXPORT Tag : public TagLib::Tag
+    {
+    public:
+      /*!
+       * Create an ID3v1 tag with default values.
+       */
+      Tag();
+
+      /*!
+       * Create an ID3v1 tag and parse the data in \a file starting at
+       * \a tagOffset.
+       */
+      Tag(File *file, long tagOffset);
+
+      /*!
+       * Destroys this Tag instance.
+       */
+      virtual ~Tag();
+
+      /*!
+       * Renders the in memory values to a ByteVector suitable for writing to
+       * the file.
+       */
+      ByteVector render() const;
+
+      /*!
+       * Returns the string "TAG" suitable for usage in locating the tag in a
+       * file.
+       */
+      static ByteVector fileIdentifier();
+
+      // Reimplementations.
+
+      virtual String title() const;
+      virtual String artist() const;
+      virtual String album() const;
+      virtual String comment() const;
+      virtual String genre() const;
+      virtual uint year() const;
+      virtual uint track() const;
+
+      virtual void setTitle(const String &s);
+      virtual void setArtist(const String &s);
+      virtual void setAlbum(const String &s);
+      virtual void setComment(const String &s);
+      virtual void setGenre(const String &s);
+      virtual void setYear(uint i);
+      virtual void setTrack(uint i);
+
+      /*!
+       * Sets the string handler that decides how the ID3v1 data will be
+       * converted to and from binary data.
+       *
+       * \see StringHandler
+       */
+      static void setStringHandler(const StringHandler *handler);
+
+    protected:
+      /*!
+       * Reads from the file specified in the constructor.
+       */
+      void read();
+      /*!
+       * Pareses the body of the tag in \a data.
+       */
+      void parse(const ByteVector &data);
+
+    private:
+      Tag(const Tag &);
+      Tag &operator=(const Tag &);
+
+      class TagPrivate;
+      TagPrivate *d;
+    };
+  }
+}
+
+#endif
diff --git a/src/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp b/src/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp
new file mode 100644 (file)
index 0000000..a763e18
--- /dev/null
@@ -0,0 +1,224 @@
+/***************************************************************************
+    copyright&n