aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/libapetag
diff options
context:
space:
mode:
Diffstat (limited to 'src/libapetag')
-rwxr-xr-xsrc/libapetag/COPYING.LGPL510
-rwxr-xr-xsrc/libapetag/Makefile.am22
-rw-r--r--src/libapetag/Makefile.in471
-rwxr-xr-xsrc/libapetag/README.apetag12
-rwxr-xr-xsrc/libapetag/apetaglib.c1065
-rwxr-xr-xsrc/libapetag/apetaglib.h277
-rwxr-xr-xsrc/libapetag/id3v2_read.c385
-rwxr-xr-xsrc/libapetag/id3v2_read.h42
-rwxr-xr-xsrc/libapetag/info_mac.c151
-rwxr-xr-xsrc/libapetag/info_mac.h96
-rwxr-xr-xsrc/libapetag/info_mpc.c198
-rwxr-xr-xsrc/libapetag/info_mpc.h96
-rwxr-xr-xsrc/libapetag/is_tag.c175
-rwxr-xr-xsrc/libapetag/is_tag.h41
14 files changed, 3541 insertions, 0 deletions
diff --git a/src/libapetag/COPYING.LGPL b/src/libapetag/COPYING.LGPL
new file mode 100755
index 0000000..cf9b6b9
--- /dev/null
+++ b/src/libapetag/COPYING.LGPL
@@ -0,0 +1,510 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 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 Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ 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 Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+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 other code 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.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ 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, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser 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.
+
+ 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.
+^L
+ 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.
+^L
+ 6. As an exception to the Sections above, you may also combine 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) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) 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.
+
+ d) 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.
+
+ e) 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 materials to be 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.
+^L
+ 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 with
+this License.
+^L
+ 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 Lesser 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.
+^L
+ 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
+^L
+ 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.1 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!
+
+
diff --git a/src/libapetag/Makefile.am b/src/libapetag/Makefile.am
new file mode 100755
index 0000000..61b0f9c
--- /dev/null
+++ b/src/libapetag/Makefile.am
@@ -0,0 +1,22 @@
+CFLAGS = @CFLAGS@ @GTK_CFLAGS@
+
+noinst_LIBRARIES = libapetag.a
+
+INCLUDES = -DLOCALE=\"$(localedir)\"
+
+
+libapetag_a_SOURCES = \
+ apetaglib.c \
+ apetaglib.h \
+ is_tag.c \
+ is_tag.h \
+ info_mac.c \
+ info_mac.h \
+ info_mpc.c \
+ info_mpc.h
+
+EXTRA_DIST = \
+ COPYING.LGPL \
+ README.apetag \
+ id3v2_read.c \
+ id3v2_read.h
diff --git a/src/libapetag/Makefile.in b/src/libapetag/Makefile.in
new file mode 100644
index 0000000..68858ad
--- /dev/null
+++ b/src/libapetag/Makefile.in
@@ -0,0 +1,471 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/libapetag
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libapetag_a_AR = $(AR) $(ARFLAGS)
+libapetag_a_LIBADD =
+am_libapetag_a_OBJECTS = apetaglib.$(OBJEXT) is_tag.$(OBJEXT) \
+ info_mac.$(OBJEXT) info_mpc.$(OBJEXT)
+libapetag_a_OBJECTS = $(am_libapetag_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libapetag_a_SOURCES)
+DIST_SOURCES = $(libapetag_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ @GTK_CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+OBJEXT = @OBJEXT@
+OGG_CFLAGS = @OGG_CFLAGS@
+OGG_LIBS = @OGG_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+VORBIS_CFLAGS = @VORBIS_CFLAGS@
+VORBIS_LIBS = @VORBIS_LIBS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+XGETTEXT = @XGETTEXT@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_pt_PKG_CONFIG = @ac_pt_PKG_CONFIG@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+noinst_LIBRARIES = libapetag.a
+INCLUDES = -DLOCALE=\"$(localedir)\"
+libapetag_a_SOURCES = \
+ apetaglib.c \
+ apetaglib.h \
+ is_tag.c \
+ is_tag.h \
+ info_mac.c \
+ info_mac.h \
+ info_mpc.c \
+ info_mpc.h
+
+EXTRA_DIST = \
+ COPYING.LGPL \
+ README.apetag \
+ id3v2_read.c \
+ id3v2_read.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/libapetag/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/libapetag/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libapetag.a: $(libapetag_a_OBJECTS) $(libapetag_a_DEPENDENCIES)
+ -rm -f libapetag.a
+ $(libapetag_a_AR) libapetag.a $(libapetag_a_OBJECTS) $(libapetag_a_LIBADD)
+ $(RANLIB) libapetag.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apetaglib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info_mac.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info_mpc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/is_tag.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/libapetag/README.apetag b/src/libapetag/README.apetag
new file mode 100755
index 0000000..9b3d311
--- /dev/null
+++ b/src/libapetag/README.apetag
@@ -0,0 +1,12 @@
+"apetaglib (in source) easytag" editon 0.5-pre1
+
+For current source mail to [artii <at> o2 <dot> pl]
+
+If you develop some nice patches or found some bugs
+please send me info ;-)
+
+All documentation fixes please send too (check all *.h files)
+
+this will be on dual licences GPL/LGPL (propably)
+
+now is LGPL
diff --git a/src/libapetag/apetaglib.c b/src/libapetag/apetaglib.c
new file mode 100755
index 0000000..1f5012e
--- /dev/null
+++ b/src/libapetag/apetaglib.c
@@ -0,0 +1,1065 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: apetaglib.c,v 1.44 2003/04/16 21:06:27 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <math.h>
+#ifndef __BORLANDC__
+# include <unistd.h>
+#endif
+#include "apetaglib.h"
+#include "../genres.h"
+
+#include "is_tag.h"
+#ifdef ID3V2_READ
+# include "id3v2_read.h"
+#endif
+
+/* LOCAL STRUCTURES */
+
+/**
+ \struct _apetag_footer
+ \brief structure of APETAGEXT footer or/and header tag
+*/
+struct _apetag_footer
+{
+ unsigned char id[8]; /**< magic should equal 'APETAGEX' */
+ unsigned char version[4]; /**< version 1000 (v1.0) or 2000 (v 2.0) */
+ unsigned char length[4]; /**< the complete size of the tag, including footer, but no header for v2.0 */
+ unsigned char tagCount[4]; /**< the number of fields in the tag */
+ unsigned char flags[4]; /**< the tag flags (none currently defined for v 1.0) */
+ unsigned char reserved[8]; /**< reserved for later use */
+};
+
+/**
+ \struct _ape_mem_cnt
+ \brief internal structure for apetag
+*/
+struct _ape_mem_cnt
+{
+ struct tag **tag;
+ int countTag;
+ int memTagAlloc; // for mem container;
+ char *filename; // for info
+ struct _apetag_footer ape_header;
+ struct _apetag_footer ape_footer;
+ int currentPosition;
+};
+
+/* *
+ \struct _id3v1Tag
+ \brief for id3v1 tag
+*/
+struct _id3v1Tag
+{
+ char magic[3]; // `TAG`
+ char title[30];
+ char artist[30];
+ char album[30];
+ char year[4];
+ char comment[30]; // if ([28]==0 and [29]!=0) track = [29]
+ unsigned char genre;
+};
+
+/* LOCAL FUNCTION prototypes */
+unsigned long
+ape2long (unsigned char *p);
+void
+long2ape (unsigned char *p, const unsigned long value);
+struct tag *
+libapetag_maloc_cont_int (apetag *mem_cnt, struct tag *mTag);
+int
+libapetag_maloc_cont_text (apetag *mem_cnt, unsigned long flags,
+ long sizeName, char *name, long sizeValue, char *value);
+int
+libapetag_maloc_cont (apetag *mem_cnt, unsigned long flags,
+ long sizeName, char *name, long sizeValue, char *value);
+static int
+libapetag_qsort (struct tag **a, struct tag **b);
+int
+make_id3v1_tag(apetag *mem_cnt, struct _id3v1Tag *m);
+
+
+unsigned long
+ape2long (unsigned char *p)
+{
+ return (((unsigned long) p[0] << 0) |
+ ((unsigned long) p[1] << 8) |
+ ((unsigned long) p[2] << 16) |
+ ((unsigned long) p[3] << 24) );
+}
+
+void
+long2ape (unsigned char *p, const unsigned long value)
+{
+ p[0] = (unsigned char) (value >> 0);
+ p[1] = (unsigned char) (value >> 8);
+ p[2] = (unsigned char) (value >> 16);
+ p[3] = (unsigned char) (value >> 24);
+}
+
+
+/*
+ PL: funkcja troszczaca sie o odpowiedni± ilosc zalokowanej pamieci dla tablicy
+ PL: %mTag% przy okazji alokuje z wyprzedzeniem troche wiecej pamieci [mniej %realoc%]
+ PL: zwraca %mTag[]%
+ :NON_USER:!!!
+ */
+#define LIBAPETAG_MEM_ALLOC_AHEAD 16 /* 15 it's good for normal #of tag, Aver 4-8 */
+struct tag *
+libapetag_maloc_cont_int (apetag *mem_cnt, struct tag *mTag)
+{
+ struct tag **tag_tmp = mem_cnt->tag;
+
+ if (mem_cnt->memTagAlloc == 0) { /* init */
+ mem_cnt->tag = (struct tag **)
+ malloc (((sizeof (struct tag **)) * (LIBAPETAG_MEM_ALLOC_AHEAD)));
+ mem_cnt->memTagAlloc = LIBAPETAG_MEM_ALLOC_AHEAD;
+ mem_cnt->countTag = 0;
+ if (mem_cnt->tag == NULL) {
+ mem_cnt->memTagAlloc = mem_cnt->countTag = 0;
+ PRINT_ERR ( "ERROR->libapetag->libapetag_maloc_cont_int:malloc\n");
+ return NULL;
+ }
+ }
+
+ if ((mem_cnt->memTagAlloc) <= (mem_cnt->countTag + 1)) {
+ mem_cnt->tag = (struct tag **) realloc (mem_cnt->tag, ((sizeof (struct tag **)) *
+ (mem_cnt->memTagAlloc + LIBAPETAG_MEM_ALLOC_AHEAD)));
+ mem_cnt->memTagAlloc += LIBAPETAG_MEM_ALLOC_AHEAD;
+ }
+
+ if (mem_cnt->tag == NULL) {
+ int n;
+
+ PRINT_ERR ( "ERROR->libapetag->libapetag_maloc_cont_int:malloc\n");
+ /* free old all */
+ for (n = mem_cnt->countTag-1; n >= 0; n--) {
+ free (tag_tmp[n]->value);
+ free (tag_tmp[n]->name);
+ free (tag_tmp[n]);
+ }
+ free (tag_tmp);
+ mem_cnt->memTagAlloc = mem_cnt->countTag = 0;
+ return NULL;
+ }
+
+ mem_cnt->tag[mem_cnt->countTag] = mTag;
+ mem_cnt->countTag++;
+ return mTag;
+
+}
+#undef LIBAPETAG_MEM_ALLOC_AHEAD
+
+
+/*
+ PL: alocuje pamiec dla %mTag% przypisuje odpowiednio wartosci
+ PL: dodaje %\0% do stringów [na wszelki wypadek]
+ PL: nie dopisuje takich samych
+ PL: wszystkie sizy maja byc bez \0 (jak bedzie to doliczy jeszcze jeden)
+ :NON_USER:!!!
+ */
+int
+libapetag_maloc_cont (apetag *mem_cnt, unsigned long flags,
+ long sizeName, char *name, long sizeValue, char *value)
+{
+ struct tag *mTag;
+ // TODO:: zadbac o to zeby tu czyscilo istniejace tagi jesli value=NULL
+ if (!sizeName || !sizeValue)
+ return ATL_BADARG;
+
+ if (apefrm_getstr (mem_cnt, name) == NULL) {
+ mTag = (struct tag *) malloc (sizeof (struct tag));
+
+ if (mTag == NULL)
+ return ATL_MALOC;
+
+ mTag->value = (char *) malloc (sizeValue + 1);
+ if (mTag->value==NULL) {
+ free (mTag);
+ return ATL_MALOC;
+ }
+
+ mTag->name = (char *) malloc (sizeName + 1);
+ if (mTag->name==NULL) {
+ free (mTag->value);
+ free (mTag);
+ return ATL_MALOC;
+ }
+
+ memcpy (mTag->value, value, sizeValue);
+ memcpy (mTag->name, name, sizeName);
+ mTag->value[sizeValue] = '\0';
+ mTag->name[sizeName] = '\0';
+ mTag->sizeName = sizeName;
+ mTag->sizeValue = sizeValue;
+ mTag->flags = flags;
+
+ if (libapetag_maloc_cont_int (mem_cnt, mTag)==NULL) {
+ PRINT_ERR(">apetaglib>libapetag_maloc_cont>> int==NULL");
+ return ATL_MALOC;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ PL: jezeli nie istnieje to dodaje taga, pomija ostatnie biale znaki
+ PL: pomija jesli pusty
+ PL: ! zmienia tekst wej¶ciowy
+ :NON_USER:!!!
+*/
+int
+libapetag_maloc_cont_text (apetag *mem_cnt, unsigned long flags,
+ long sizeName, char *name, long sizeValue,
+ char *value)
+{
+ int n = sizeValue;
+
+ if (value != NULL && value[0] != '\0' && apefrm_getstr (mem_cnt, name) == NULL) {
+ while (value[--n] == ' ' || value[n] == '\0' || value[n] == '\n') {
+ value[n] = '\0';
+ }
+ return libapetag_maloc_cont (mem_cnt, flags, sizeName, name, n + 1, value);
+ }
+
+ return 0;
+}
+
+
+/*
+ PL: dodaje taga do istniejeacych o ustawionych wartosciach %flag% %name% i %value%
+ PL: wylicza odpowiednio rozmiary przy pomocy strlen!!
+ PL: wraper na %libapetag_maloc_cont%
+ PL: wszystko kopiuje sobie do pamieci
+ PL: musi byc juz w UTF-8 dla v2
+ PL: Nadpisuje istniejace
+ */
+/**
+ \brief Add text frame
+
+ add text frame/field to object apetag (if exist then overwrite)
+
+ \param mem_cnt object #apetag
+ \param flags flags stored in frame
+ \param name name of frame
+ \param value value of frame
+ \return 0 - OK else check #atl_return
+*/
+int
+apefrm_add (apetag *mem_cnt, unsigned long flags, char *name,
+ char *value)
+{
+ apefrm_remove_real (mem_cnt, name);
+ return libapetag_maloc_cont (mem_cnt, flags, strlen (name), name, strlen (value), value);
+}
+
+/*
+ PL: Prosty wraperek na maloc_cont - do zapisu binarnych
+*/
+/**
+ \brief add binary frame
+
+ add binary frame/field to object apetag (if exist then overwrite)
+
+ \param mem_cnt object #apetag
+ \param flags flags stored in frame
+ \param sizeName size of name
+ \param name name of frame
+ \param sizeValue size of value
+ \param value value of frame
+ \return 0 - OK else check #atl_return
+*/
+int
+apefrm_add_bin (apetag *mem_cnt, unsigned long flags,
+ long sizeName, char *name,
+ long sizeValue, char *value)
+{
+ apefrm_remove_real (mem_cnt, name);
+ return libapetag_maloc_cont (mem_cnt, flags, sizeName, name, sizeValue, value);
+}
+
+/*
+ PL: jak %apefrm_add ()% z tym ze nie nadpisuje istniejacych
+*/
+/**
+ \brief add frame if other (the same name) no exist
+
+ if exist "name" in ape_mem then do nothing else add frame/field to ape_mem
+
+ \param mem_cnt object #apetag
+ \param flags flags stored in frame
+ \param name name of frame
+ \param value value of frame
+ \return 0 - OK else check #atl_return
+*/
+int
+apefrm_add_noreplace (apetag *mem_cnt, unsigned long flags,
+ char *name, char *value)
+{
+ if ( apefrm_getstr (mem_cnt, name) == NULL )
+ return apefrm_add (mem_cnt, flags, name, value);
+
+ return 0;
+}
+
+/*
+ PL: wyszukuje taga o nazwie %name% i zwraca structure %struct tag%
+ PL: %APE_TAG_LIB_FIRST% i %APE_TAG_LIB_NEXT% to ulatwienie dla
+ PL: przesukiwania wszystkich istniejacych tagów
+ PL: %APE_TAG_LIB_FIRST% ustawia znacznik na pierwszy tag [0] i zwraca jego warto¶æ
+ PL: %APE_TAG_LIB_NEXT% podaje nastepny tag i zwieksza znacznik, po ostatnim funkcja zwraca %NULL%
+ PL: UWAGA!!! zwraca pointer do wewnetrznej struktury
+ PL: niczego nie zmieniac i nie free()-jowac skopiowac i dopiero
+ PL: zwraca teksty w UTF-8
+ */
+/**
+ \brief search in apetag for name and return tag
+
+ 2 special names \a APE_TAG_LIB_FIRST and \a APE_TAG_LIB_NEXT.
+ FIRST return first frame and set counter to 1
+ NEXT return ++counter frame
+\code
+for ((framka = apefrm_get(ape, APE_TAG_LIB_FIRST)); framka!=NULL;) {
+ do_something();
+ framka = apefrm_get(ape, APE_TAG_LIB_NEXT);
+}
+\endcode
+ return NULL if no more frame exist
+
+ \param mem_cnt object #apetag
+ \param name frame name for search
+ \return pointer to struct tag if name exist or NULL if don't
+ \warning don't change anything in this struct make copy and work
+*/
+struct tag *
+apefrm_get (apetag *mem_cnt, char *name)
+{
+ int n;
+ struct tag **mTag;
+
+ mTag = (mem_cnt->tag);
+
+ if (mem_cnt->countTag == 0)
+ return NULL;
+
+ if (strcmp (name, APE_TAG_LIB_FIRST) == 0) {
+ mem_cnt->currentPosition = 0;
+ return (mTag[mem_cnt->currentPosition++]);
+ }
+
+ if (strcmp (name, APE_TAG_LIB_NEXT) == 0) {
+ if (mem_cnt->currentPosition >= mem_cnt->countTag)
+ return NULL;
+ return (mTag[mem_cnt->currentPosition++]);
+ }
+
+ for (n = 0; (mem_cnt->countTag) > n; n++) {
+ if (strcasecmp (mTag[n]->name, name) == 0) {
+ return (mTag[n]);
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ PL:zwraca %mem_cnt->tag[x]->value% o ile znajdzie nazwe %name% taga
+ PL: prosty wraper na %apefrm_get %
+ PL: UWAGA zwraca pointer z wewnetrznych struktur niczego bezposrednio nie zmieniac
+ PL: i nie free()-jowac bo sie rozsypie
+ PL: zwraca tekst w UTF-8
+ */
+/**
+ \brief search in apetag for name and return string
+
+ \param mem_cnt object #apetag
+ \param name frame name for search
+ \return pointer to value of frame if name exist or NULL if don't
+ \warning don't change that string make copy before any action
+ \todo check if frame type isn't binary
+*/
+char *
+apefrm_getstr (apetag *mem_cnt, char *name)
+{
+ struct tag *mTag;
+
+ mTag = apefrm_get (mem_cnt, name);
+
+ if (mTag == NULL)
+ return NULL;
+
+ return (mTag->value);
+}
+
+/*
+ PL: usuwanie taga o nazwie zdefiniowanej w %name%
+ PL:lub wszystkich jezeli %name%=%APE_TAG_LIB_DEL_ALL%
+ PL:UWAGA mozna to napisac inaczej (sprawdzanie czy %name% OR %%special%) ale to w v1.0
+ */
+/**
+ \brief remove frame from memory
+
+ (real) remove frame from ape_mem.
+ Check #apefrm_remove for more info
+
+ \param mem_cnt object #apetag
+ \param name frame name for search and remove
+*/
+void
+apefrm_remove_real (apetag *mem_cnt, char *name)
+{
+ int n;
+ struct tag **mTag;
+
+ mTag = (mem_cnt->tag);
+
+ /* Delete all */
+ if (strcmp (name, APE_TAG_LIB_DEL_ALL) == 0) {
+ for (n = mem_cnt->countTag-1; n >= 0; n--) {
+ free (mTag[n]->name);
+ free (mTag[n]->value);
+ free (mTag[n]);
+ --mem_cnt->countTag;
+ }
+ return;
+ }
+ /* Delete only one */
+ for (n = mem_cnt->countTag-1; n >= 0; n--) {
+ if (strcasecmp (mTag[n]->name, name) == 0) {
+ free (mTag[n]->name);
+ free (mTag[n]->value);
+ free (mTag[n]);
+ mTag[n] = mTag[mem_cnt->countTag];
+ --mem_cnt->countTag;
+ /* !no return; search for all */
+ }
+ }
+
+ return;
+}
+/*
+ PL: tak jakby frejuje framke oznacza do kasacji jednak tego nie robi
+ PL: mechanizm ten g³ownie jest wykorzystywany do wczytania innych tagów
+ PL: poza wczesniej zkasowanymi aby to usun±c uzyj apefrm_remove_real
+*/
+/**
+ \brief set frame to remove
+
+ Create fake name and empty value (and set don't save flag).
+ If you use apefrm_add_norepleace then you don't change
+ this not_save_flag.
+ Only apefrm_add overwrite this.
+ [it's for id3v1 but you may using this for remove frames]
+
+ \param mem_cnt object #apetag
+ \param name frame name for search and remove
+*/
+void
+apefrm_remove (apetag *mem_cnt, char *name)
+{
+ int n;
+ struct tag **mTag;
+
+ apefrm_add (mem_cnt, 0 , name, "delete me");
+
+ mTag = (mem_cnt->tag);
+
+ for (n = 0; (mem_cnt->countTag) > n; n++) {
+ if (strcasecmp (mTag[n]->name, name) == 0) {
+ mTag[n]->sizeValue=0;
+ return;
+ }
+ }
+
+ return;
+}
+
+/*
+ PL:Wypisuje na ekran wszystko to co potrzebne do debugu
+ :NON_USER:!!!
+*/
+/**
+ debug function print all tags exclude bin (print only size for bin)
+*/
+void
+libapetag_print_mem_cnt (apetag *mem_cnt)
+{
+ int n;
+ struct tag **mTag;
+
+ mTag = (mem_cnt->tag);
+ for (n = 0; (mem_cnt->countTag) > n; n++) {
+ if ( (mTag[n]->flags & ~ITEM_TEXT) == 0 ||
+ (mTag[n]->flags & ~ITEM_LINK) == 0 ) {
+ printf (">apetaglib>PRINT>>F=%li SN=%li SV=%li N[%s] V[%s]\n",
+ mTag[n]->flags,
+ (long) mTag[n]->sizeName, (long) mTag[n]->sizeValue,
+ mTag[n]->name, mTag[n]->value);
+ } else {
+ printf (">apetaglib>PRINT>>F=%li SN=%li SV=%li N[%s] V=BINARY\n",
+ mTag[n]->flags,
+ (long) mTag[n]->sizeName, (long) mTag[n]->sizeValue,
+ mTag[n]->name);
+ }
+ }
+
+ return;
+}
+
+/*
+ PL: alokuje pamiec dla glównej struktury %struct ape_mem_cnt%
+ PL: i zeruje wszystko co trzeba
+ PL: z jakiegos powodu (mojej niewiedzy) memset nie dziala
+ PL: a w sumie dziala czyszczac troche za duzo
+*/
+/**
+ \brief initialise new object #apetag and return
+ \return new initialised object #apetag
+*/
+apetag *
+apetag_init (void)
+{
+ apetag * mem_cnt;
+
+ mem_cnt = (apetag *) malloc (sizeof (apetag));
+ if (mem_cnt == NULL) {
+ PRINT_ERR ("ERROR->libapetag->apetag_init:malloc\n");
+ return NULL;
+ }
+ mem_cnt->memTagAlloc = 0;
+ mem_cnt->countTag = 0;
+ mem_cnt->filename = NULL;
+ mem_cnt->currentPosition = 0;
+ mem_cnt->tag = NULL;
+
+ return mem_cnt;
+}
+
+/*
+ PL: Czysci z sila wodospadu wszystko co zostalo do czyszczenia
+ PL: z %struct ape_mem_cnt% wlacznie, wcze¶niej to nie by³o jasne
+*/
+/**
+ \brief free all work
+ \param mem_cnt object #apetag
+*/
+void
+apetag_free (apetag *mem_cnt)
+{
+ int n;
+
+ for (n = mem_cnt->countTag-1; n >= 0; n--)
+ {
+ free (mem_cnt->tag[n]->value);
+ free (mem_cnt->tag[n]->name);
+ free (mem_cnt->tag[n]);
+ }
+ free (mem_cnt->tag);
+ free (mem_cnt);
+ mem_cnt = NULL;
+
+ return;
+
+}
+
+
+/**
+ \brief read id3v1 and add frames
+
+ read id3v1 and add frames to ape_mem.
+ Using #apefrm_add_norepleace
+
+ \param mem_cnt object #apetag
+ \param fp file pointer
+ \return 0 - OK else check #atl_return
+*/
+int
+readtag_id3v1_fp (apetag *mem_cnt, FILE * fp)
+{
+ struct _id3v1Tag m;
+
+ if (!is_id3v1(fp))
+ return 0; /* TODO:: 0 or no_id3v1*/
+
+ fseek(fp, -128, SEEK_END);
+ if (sizeof (struct _id3v1Tag)!=fread(&m, 1, sizeof (struct _id3v1Tag), fp)){
+ PRINT_ERR( "ERROR->libapetag->readtag_id3v1_fp:fread\n");
+ return ATL_FREAD;
+ }
+
+ libapetag_maloc_cont_text(mem_cnt, 0, 5, "Title", 30, m.title);
+ libapetag_maloc_cont_text(mem_cnt, 0, 6, "Artist", 30, m.artist);
+ libapetag_maloc_cont_text(mem_cnt, 0, 5, "Album", 30, m.album);
+ libapetag_maloc_cont_text(mem_cnt, 0, 4, "Year", 4, m.year);
+ if (m.comment[28] == 0 && m.comment[29] != 0) {
+ char track[20];
+ snprintf(track, 19, "%i", m.comment[29]);
+ libapetag_maloc_cont_text(mem_cnt, 0, 5, "Track", strlen(track), track);
+ libapetag_maloc_cont_text(mem_cnt, 0, 7, "Comment", 28, m.comment);
+ } else {
+ libapetag_maloc_cont_text(mem_cnt, 0, 7, "Comment", 30, m.comment);
+ }
+ libapetag_maloc_cont_text(mem_cnt, 0, 5, "Genre",
+ strlen(genre_no(m.genre)), genre_no(m.genre));
+
+ return 0;
+}
+
+/*
+ PL: wczytuje odpowiednie fra(mk)gi do pamieci w razie koniecznosci przyciecia
+ PL: dodaje "..." na koniec
+ PL: TODO genre
+
+ PL: macro COMPUTE_ID3V1_TAG
+*/
+#define COMPUTE_ID3V1_TAG(FramkA, TagNamE, SizE, TagValuE) \
+ FramkA = apefrm_get(mem_cnt, TagNamE); \
+ if (FramkA != NULL) { \
+ memcpy (TagValuE, FramkA->value, \
+ ((FramkA->sizeValue) > SizE) ? SizE : FramkA->sizeValue ); \
+ if ((FramkA->sizeValue) > SizE) { \
+ TagValuE[SizE-1]='.'; TagValuE[SizE-2]='.'; TagValuE[SizE-3]='.'; \
+ } \
+ }
+
+int
+make_id3v1_tag(apetag *mem_cnt, struct _id3v1Tag *m)
+{
+ struct tag * framka;
+
+ if (m == NULL)
+ return ATL_BADARG;
+
+ memset(m, '\0', sizeof(struct _id3v1Tag));
+
+ memcpy (m->magic,"TAG",3);
+ COMPUTE_ID3V1_TAG(framka, "Title", 30, m->title);
+ COMPUTE_ID3V1_TAG(framka, "Artist", 30, m->artist);
+ COMPUTE_ID3V1_TAG(framka, "Album", 30, m->album);
+ COMPUTE_ID3V1_TAG(framka, "Year", 4, m->year);
+
+ if ((framka=apefrm_get(mem_cnt, "Track"))!=NULL) {
+ m->comment[29]=(unsigned char) atoi(framka->value);
+ m->comment[28]='\0';
+ COMPUTE_ID3V1_TAG(framka, "Comment", 28, m->comment);
+ } else {
+ COMPUTE_ID3V1_TAG(framka, "Comment", 30, m->comment);
+ }
+
+ return 0;
+}
+
+/*
+ PL: silnik tego liba
+ PL: %filename% jest w tej chwili tylko dla id3v2 f..k
+ PL: %ape_mem_cnt% moze byc nie zainicjalizowany ale wtedy musi byc = NULL
+*/
+/**
+ \brief read file and add frames
+
+ \param mem_cnt object #apetag
+ \param filename
+ \param fp
+ \param flag
+ \return 0 - OK else check #atl_return
+*/
+int
+apetag_read_fp(apetag *mem_cnt, FILE * fp, char *filename, int flag)
+{
+ int id3v1 = 0;
+ int apeTag2 = 0;
+ unsigned char *buff;
+ struct _apetag_footer ape_footer;
+ size_t savedFilePosition, buffLength;
+
+ unsigned char *end;
+ unsigned long tagCount;
+ unsigned char *p;
+
+ savedFilePosition = ftell(fp);
+
+ id3v1 = is_id3v1(fp);
+
+ if (mem_cnt == NULL) {
+ PRINT_ERR( ">apetaglib>READ_FP>FATAL>apetag_init()\n");
+ fseek(fp, savedFilePosition, SEEK_SET);
+ return ATL_NOINIT;
+ }
+
+ fseek(fp, id3v1 ? -128 - sizeof (ape_footer) : -sizeof (ape_footer), SEEK_END);
+ if (sizeof (ape_footer) != fread(&ape_footer, 1, sizeof (ape_footer), fp)){
+ PRINT_ERR( "ERROR->libapetag->apetag_read_fp:fread1\n");
+ fseek(fp, savedFilePosition, SEEK_SET);
+ return ATL_FREAD;
+ }
+
+ if (!(flag & DONT_READ_TAG_APE) &&
+ (memcmp(ape_footer.id, "APETAGEX", sizeof (ape_footer.id)) == 0))
+ {
+ PRINT_D9(">apetaglib>READ_FP>>%s: ver %li len %li # %li fl %lx v1=%i v2=%i ape=%i[v%i]\n",
+ filename, ape2long(ape_footer.version),
+ ape2long(ape_footer.length),
+ ape2long(ape_footer.tagCount),
+ ape2long(ape_footer.flags),
+ is_id3v1 (fp), is_id3v2 (fp), is_ape (fp), is_ape_ver (fp));
+
+ apeTag2 = ape2long(ape_footer.version);
+ buffLength = is_ape(fp) + 128;
+ buff = (unsigned char *) malloc(buffLength);
+ if (buff == NULL) {
+ PRINT_ERR( "ERROR->libapetag->apetag_read_fp:malloc\n");
+ return ATL_MALOC;
+ }
+
+ fseek(fp, id3v1 ? -ape2long(ape_footer.length) -
+ 128 : -ape2long(ape_footer.length), SEEK_END);
+ memset(buff, 0, buffLength);
+ if (ape2long(ape_footer.length) != fread(buff, 1, ape2long(ape_footer.length), fp)) {
+ PRINT_ERR( "ERROR->libapetag->apetag_read_fp:fread2\n");
+ fseek(fp, savedFilePosition, SEEK_SET);
+ free(buff);
+ return ATL_FREAD;
+ }
+
+ tagCount = ape2long(ape_footer.tagCount);
+
+ end = buff + ape2long(ape_footer.length) - sizeof (ape_footer);
+
+ for (p = buff; p < end && tagCount--;) {
+ /* 8 = sizeof( sizeValue+flags ) */
+ unsigned long flag = ape2long(p + 4);
+ unsigned long sizeValue = ape2long(p);
+ unsigned long sizeName;
+ char *name = p + 8;
+ char *value;
+
+ sizeName = strlen(p + 8);
+ value = p + sizeName + 8 + 1;
+ if (apeTag2 == 1000 && value[sizeValue - 1] == '\0') {
+ libapetag_maloc_cont(mem_cnt, flag,
+ sizeName, name,
+ sizeValue - 1, value);
+ } else {
+ libapetag_maloc_cont(mem_cnt, flag,
+ sizeName, name,
+ sizeValue, value);
+ }
+ p += (sizeName + sizeValue + 8 + 1);
+ }
+
+ free(buff);
+ } else { /* if no ape tag */
+ PRINT_D5(">apetaglib>READ_FP>>%s: v1=%i v2=%i ape=%i[v%i]\n",
+ filename, is_id3v1 (fp), is_id3v2 (fp), is_ape (fp), is_ape_ver (fp));
+ }
+
+#ifdef ID3V2_READ
+ if (!(flag & DONT_READ_TAG_ID3V2) && filename!=NULL && is_id3v2(fp)!=0) {
+ readtag_id3v2(mem_cnt, filename);
+ }
+#endif
+ if (!(flag & DONT_READ_TAG_ID3V1) && (id3v1)) {
+ readtag_id3v1_fp(mem_cnt, fp);
+ }
+
+ fseek(fp, savedFilePosition, SEEK_SET);
+ return 0;
+}
+
+/*
+ PL: wraper na apetag_read_fp
+ PL: otwiera plik wczytuje co trzeba i zamyka
+ PL: dobre do wczytywania informacji ktore sa potrzebne pozniej bez fatygi otwierania pliku
+*/
+/**
+ \brief read file and add frames
+
+ \param mem_cnt object #apetag
+ \param filename file name
+ \param flag
+ \return 0 - OK else check #atl_return
+*/
+int
+apetag_read (apetag *mem_cnt, char *filename,int flag)
+{
+ FILE *fp;
+
+ if (mem_cnt==NULL) {
+ PRINT_ERR(">apetaglib>READ>FATAL>apetag_init()\n");
+ return ATL_NOINIT;
+ }
+
+ fp = fopen (filename, "rb");
+ if (fp == NULL)
+ return ATL_FOPEN;
+
+ apetag_read_fp (mem_cnt, fp, filename,flag);
+
+ fclose (fp);
+
+ return 0;
+}
+
+/*
+ PL: Funkcja dla qsorta ze specjalnymi wyjatkami
+ PL: uzywana w apetag_save
+ :NON_USER:!!!
+*/
+static int
+libapetag_qsort (struct tag **a, struct tag **b)
+{
+ char *sorting[] = { "Artist", "Year", "Album", "Track", "Title", "Genre", NULL, NULL };
+ int n, m;
+
+ if (!a || !b || !*a || !*b) {
+ PRINT_ERR ("ERROR->libapetag->apetag_qsort:*a ||*b = NULL : FATAL PLEASE REPORT!!!\n");
+ return 0;
+ }
+ for (n = 0; sorting[n] != NULL; n++) {
+ if (strcasecmp ((*a)->name, sorting[n]) == 0)
+ break;
+ }
+ if (sorting[n] == NULL)
+ n += (*a)->sizeValue + 1; /* n = max entries of sorting + size of tag */
+
+ for (m = 0; sorting[m] != NULL; m++) {
+ if (strcasecmp ((*b)->name, sorting[m]) == 0)
+ break;
+ }
+ if (sorting[m] == NULL)
+ m += (*b)->sizeValue + 1; /* m = max entries */
+
+ if (n == m)
+ return 0;
+ if (n > m)
+ return 1;
+ else
+ return -1;
+}
+
+#ifdef USE_CHSIZE
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <io.h>
+/* on winblows we don't have truncate (and ftruncate) but have chsize() */
+void
+truncate (char *filename, size_t fileSize)
+{
+ int handle;
+
+ handle = open (filename, O_RDWR | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ if (handle != -1) {
+ if (chsize (handle, fileSize) != 0) {
+ PRINT_ERR ("Error truncatng file\n");
+ }
+ close (handle);
+ }
+
+}
+
+#endif
+
+/*
+ PL: domyslne %flag% = APE_TAG_V2 + SAVE_NEW_OLD_APE_TAG
+*/
+/**
+ \brief save apetag to file
+
+ \param filename file name
+ \param mem_cnt object #apetag
+ \param flag flags for read/save
+ \return 0 - OK else check #atl_return
+ \warning for ape tag v 1 you must add frames in iso-1
+ for v 2 this must be in utf-8
+ \todo PL: v9 sprawdzac flagi w footer i na tej podstawie zmieniac skipBytes
+ bez domniemywania ze v2 ma zawsze oba
+
+*/
+int
+apetag_save (char *filename, apetag *mem_cnt, int flag)
+{
+ FILE *fp;
+ struct _id3v1Tag id3v1_tag;
+ int id3v1;
+ int apeTag, saveApe2;
+ int tagCount = 0;
+ int realCountTag = 0;
+ struct _apetag_footer ape_footer;
+ long skipBytes;
+ unsigned char *buff, *p;
+ struct tag **mTag;
+ size_t tagSSize = 32;
+ int n;
+ char temp[4];
+
+ if (mem_cnt==NULL) {
+ PRINT_ERR("ERROR->apetaglib>apetag_save::apetag_init()\n");
+ return ATL_NOINIT;
+ }
+
+ fp = fopen (filename, "rb+");
+ if (fp == NULL) {
+ PRINT_ERR ( "ERROR->apetaglib->apetag_save::fopen (r+)\n");
+ return ATL_FOPEN;
+ }
+
+ skipBytes = 0;
+ id3v1 = is_id3v1 (fp);
+ apeTag = is_ape (fp);
+ saveApe2 = !(flag & APE_TAG_V1); // (flag & APE_TAG_V2) ? 1 : (flag & APE_TAG_V1);
+
+ if (id3v1) {
+ fseek (fp, -128, SEEK_END);
+ fread (&id3v1_tag, 1, sizeof (struct _id3v1Tag), fp);
+ skipBytes += id3v1;
+ }
+ skipBytes += apeTag;
+
+ if (!(flag & SAVE_NEW_APE_TAG)) {
+ apetag_read_fp (mem_cnt, fp, filename, flag);
+ }
+
+ mTag = (mem_cnt->tag);
+ qsort( mTag , mem_cnt->countTag , sizeof(struct tag *),
+ (int (*)(const void *,const void *))libapetag_qsort);
+
+ for (n = 0; (mem_cnt->countTag) > n; n++) {
+ if (mTag[n]->sizeValue != 0) {
+ tagSSize += ((long) mTag[n]->sizeName + (long) mTag[n]->sizeValue);
+ tagSSize += 4 + 4 + 1 + (saveApe2 ? 0 : 1); // flag & sizeValue & \0
+ realCountTag++; // count not deleted tag (exl. not real)
+ }
+ }
+ if (!!(flag & SAVE_CREATE_ID3V1_TAG )) {
+ make_id3v1_tag(mem_cnt, &id3v1_tag);
+ tagSSize += 128;
+ }
+ //PRINT_D4 (">apetaglib>SAVE>>: size %li %i %i %i\n", tagSSize,
+ // mem_cnt->countTag, flag, saveApe2);
+ buff = (unsigned char *) malloc (tagSSize + (saveApe2 ? 32 : 0));
+ p = buff;
+
+ if (buff == NULL) {
+ PRINT_ERR ("ERROR->libapetag->apetag_save::malloc");
+ return ATL_MALOC;
+ }
+ memset (ape_footer.id, 0, sizeof (ape_footer));
+ memcpy (ape_footer.id, "APETAGEX", sizeof (ape_footer.id));
+ long2ape (ape_footer.flags, 0l);
+ if (!!(flag & SAVE_CREATE_ID3V1_TAG ))
+ long2ape (ape_footer.length, tagSSize-128);
+ else
+ long2ape (ape_footer.length, tagSSize);
+ //long2ape(ape_footer.tagCount, mem_cnt->countTag);
+ long2ape(ape_footer.tagCount, realCountTag);
+ long2ape (ape_footer.version, (saveApe2 ? 2000 : 1000));
+ if (saveApe2) {
+ long2ape (ape_footer.flags, HEADER_THIS_IS + HEADER_IS + FOOTER_IS);
+ memcpy (p, ape_footer.id, sizeof (ape_footer));
+ p += sizeof (ape_footer);
+ }
+
+ mTag = (mem_cnt->tag);
+ for (n = 0; (mem_cnt->countTag) > n; n++) {
+ if (saveApe2) {
+ long2ape (temp, mTag[n]->sizeValue);
+ } else {
+ /* TODO:convert UTF8 to ASCII mTag[n]->value */
+ long2ape (temp, (mTag[n]->sizeValue) + 1);
+ }
+
+ if (mTag[n]->sizeValue != 0) {
+ memcpy (p, temp, 4);
+ p += 4;
+ long2ape (temp, (saveApe2!=0) ? mTag[n]->flags : 0l );
+ memcpy (p, temp, 4);
+ p += 4;
+
+ memcpy (p, mTag[n]->name, mTag[n]->sizeName);
+ p += mTag[n]->sizeName;
+ memcpy (p, "\0", 1);
+ p++;
+ memcpy (p, mTag[n]->value, mTag[n]->sizeValue);
+ p += mTag[n]->sizeValue;
+
+ if (!saveApe2) {
+ memcpy (p, "\0", 1);
+ p++;
+ }
+ tagCount++;
+ }
+ } /* for */
+
+ if (saveApe2)
+ long2ape (ape_footer.flags, FOOTER_THIS_IS + FOOTER_IS + HEADER_IS);
+
+ memcpy (p, ape_footer.id, sizeof (ape_footer));
+ p += sizeof (ape_footer);
+
+ if (!!(flag & SAVE_CREATE_ID3V1_TAG )) {
+ memcpy (p, &id3v1_tag , sizeof (struct _id3v1Tag));
+ }
+
+ /* write tag to file and truncate */
+ if (!(flag & SAVE_FAKE_SAVE)) {
+ size_t fileSize;
+ size_t newFileSize;
+ size_t writedBytes;
+
+ fseek (fp, 0, SEEK_END);
+ fileSize = ftell (fp);
+ fseek (fp, fileSize - skipBytes, SEEK_SET);
+ if (tagCount != 0) {
+ newFileSize = (fileSize - skipBytes + tagSSize + (saveApe2 ? 32 : 0));
+ writedBytes = fwrite (buff, 1, tagSSize + (saveApe2 ? 32 : 0), fp);
+ if (writedBytes != tagSSize + (saveApe2 ? 32 : 0)) {
+ PRINT_ERR ("FATAL_ERROR->libapetag->apetag_save::fwrite [data lost]");
+ fclose (fp);
+ free (buff);
+ return ATL_FWRITE;
+ }
+ fseek (fp, newFileSize, SEEK_SET);
+ PRINT_D4 (">apetaglib>SAVE>> write:%i == tag:%i file: %i->%i\n",
+ writedBytes, tagSSize + (saveApe2 ? 32 : 0), fileSize, newFileSize);
+ } else {
+ newFileSize = (fileSize - skipBytes);
+ }
+ fflush (fp);
+ fclose (fp);
+ /* ftruncate don't work */
+ truncate (filename, newFileSize);
+ } else { /* !!SAVE_FAKE_SAVE */
+ libapetag_print_mem_cnt (mem_cnt);
+ }
+ free (buff);
+
+ return 0;
+}
diff --git a/src/libapetag/apetaglib.h b/src/libapetag/apetaglib.h
new file mode 100755
index 0000000..15ec6e9
--- /dev/null
+++ b/src/libapetag/apetaglib.h
@@ -0,0 +1,277 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: apetaglib.h,v 1.30 2003/04/16 21:06:27 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _APETAGLIB_H
+#define _APETAGLIB_H
+
+/** \file
+ \brief All function related to apetag
+*/
+
+// Uncomment this line to enable debug messages
+//#define APE_TAG_DEBUG
+
+#ifdef __WATCOMC__ // Watcom don't like || in ifdef and use #if define() || define()
+#define USE_CHSIZE
+#define strcasecmp(a,b) stricmp(a,b)
+#define index(a,b) strchr(a,b)
+#endif
+
+#ifdef __WIN32__
+#define USE_CHSIZE
+#define strcasecmp(a,b) stricmp(a,b)
+#define index(a,b) strchr(a,b)
+#define S_IRGRP S_IRUSR
+#define S_IWGRP S_IWUSR
+#endif
+
+/**\{*/
+#ifdef APE_TAG_DEBUG
+#define PRINT_D(x) fprintf( stdout, x )
+#define PRINT_D1(x,a) fprintf( stdout, x, a )
+#define PRINT_D2(x,a,b) fprintf( stdout, x, a,b)
+#define PRINT_D3(x,a,b,c) fprintf( stdout, x, a,b,c)
+#define PRINT_D4(x,a,b,c,d) fprintf( stdout, x, a,b,c,d)
+#define PRINT_D5(x,a,b,c,d,e) fprintf( stdout, x, a,b,c,d,e)
+#define PRINT_D6(x,a,b,c,d,e,f) fprintf( stdout, x, a,b,c,d,e,f)
+#define PRINT_D7(x,a,b,c,d,e,f,g) fprintf( stdout, x, a,b,c,d,e,f,g)
+#define PRINT_D8(x,a,b,c,d,e,f,g,i) fprintf( stdout, x, a,b,c,d,e,f,g,i)
+#define PRINT_D9(x,a,b,c,d,e,f,g,i,j) fprintf( stdout, x ,a,b,c,d,e,f,g,i,j )
+#else
+#define PRINT_D(x)
+#define PRINT_D1(x,a)
+#define PRINT_D2(x,a,b)
+#define PRINT_D3(x,a,b,c)
+#define PRINT_D4(x,a,b,c,d)
+#define PRINT_D5(x,a,b,c,d,e)
+#define PRINT_D6(x,a,b,c,d,e,f)
+#define PRINT_D7(x,a,b,c,d,e,f,g)
+#define PRINT_D8(x,a,b,c,d,e,f,g,i)
+#define PRINT_D9(x,a,b,c,d,e,f,g,i,j)
+#endif /*APE_TAG_DEBUG*/
+
+#define PRINT_ERR(x) fprintf( stderr, x )
+#define PRINT_ERR1(x, a) fprintf( stderr, x ,a)
+/**\}*/
+
+/** version of apetaglib defined in one place */
+#define APETAGLIB_VERSION "0.5pre1"
+
+
+/*from winamp mpc plugin*/
+/** \name frame names */
+/**\{*/
+#define APE_TAG_FIELD_TITLE "Title"
+#define APE_TAG_FIELD_SUBTITLE "Subtitle"
+#define APE_TAG_FIELD_ARTIST "Artist"
+#define APE_TAG_FIELD_ALBUM "Album"
+#define APE_TAG_FIELD_DEBUTALBUM "Debut Album"
+#define APE_TAG_FIELD_PUBLISHER "Publisher"
+#define APE_TAG_FIELD_CONDUCTOR "Conductor"
+#define APE_TAG_FIELD_COMPOSER "Composer"
+#define APE_TAG_FIELD_COMMENT "Comment"
+#define APE_TAG_FIELD_YEAR "Year"
+#define APE_TAG_FIELD_RECORDDATE "Record Date"
+#define APE_TAG_FIELD_RECORDLOCATION "Record Location"
+#define APE_TAG_FIELD_TRACK "Track"
+#define APE_TAG_FIELD_GENRE "Genre"
+#define APE_TAG_FIELD_COVER_ART_FRONT "Cover Art (front)"
+#define APE_TAG_FIELD_NOTES "Notes"
+#define APE_TAG_FIELD_LYRICS "Lyrics"
+#define APE_TAG_FIELD_COPYRIGHT "Copyright"
+#define APE_TAG_FIELD_PUBLICATIONRIGHT "Publicationright"
+#define APE_TAG_FIELD_FILE "File"
+#define APE_TAG_FIELD_MEDIA "Media"
+#define APE_TAG_FIELD_EANUPC "EAN/UPC"
+#define APE_TAG_FIELD_ISRC "ISRC"
+#define APE_TAG_FIELD_RELATED_URL "Related"
+#define APE_TAG_FIELD_ABSTRACT_URL "Abstract"
+#define APE_TAG_FIELD_BIBLIOGRAPHY_URL "Bibliography"
+#define APE_TAG_FIELD_BUY_URL "Buy URL"
+#define APE_TAG_FIELD_ARTIST_URL "Artist URL"
+#define APE_TAG_FIELD_PUBLISHER_URL "Publisher URL"
+#define APE_TAG_FIELD_FILE_URL "File URL"
+#define APE_TAG_FIELD_COPYRIGHT_URL "Copyright URL"
+#define APE_TAG_FIELD_INDEX "Index"
+#define APE_TAG_FIELD_INTROPLAY "Introplay"
+#define APE_TAG_FIELD_MJ_METADATA "Media Jukebox Metadata"
+#define APE_TAG_FIELD_DUMMY "Dummy"
+/**\}*/
+
+#define APE_TAG_LIB_FIRST "\02" /**< is using by #apefrm_get to get first frame */
+#define APE_TAG_LIB_NEXT "\03" /**< is using by #apefrm_get to get next frame you may check all frames this way */
+#define APE_TAG_LIB_DEL_ALL "\04" /**< is using by #apefrm_remove_real for removing all frames */
+
+
+/**
+ \name #apetag_save flags
+ \note default is #APE_TAG_V2 + #SAVE_NEW_OLD_APE_TAG + #SAVE_REMOVE_ID3V1
+*/
+/**\{*/
+#define APE_TAG_V1 (1 << 1)
+#define APE_TAG_V2 (1 << 2)
+#define SAVE_NEW_APE_TAG (1 << 3)
+#define SAVE_NEW_OLD_APE_TAG (1 << 4)
+#define SAVE_REMOVE_ID3V1 (1 << 5)
+#define SAVE_CREATE_ID3V1_TAG (1 << 6)
+#define SAVE_FAKE_SAVE (1 << 7)
+/* apetag_read(_fp) flags - default read all (ape,id3v1,id3v2(if compiled)) */
+#define DONT_READ_TAG_APE (1 << 8)
+#define DONT_READ_TAG_ID3V1 (1 << 9)
+#define DONT_READ_TAG_ID3V2 (1 << 10)
+/**\}*/
+
+
+/**
+ \name #atl_return
+ \brief return codes from all functions
+ \{
+*/
+#define ATL_OK 0 /**< not using :) */
+#define ATL_FOPEN 1 /**< can't open file */
+#define ATL_FREAD 2 /**< can't read from file */
+#define ATL_FWRITE 3 /**< can't write to file (written bytes != bytes to write) */
+#define ATL_MALOC 4 /**< can't allocate memory */
+#define ATL_BADARG 5 /**< bad function argument */
+#define ATL_NOINIT 6 /**< not inited struct by apetag_init */
+/** \} */
+
+/**
+ \struct tag
+ \brief tag structure
+
+ i you get this <b>don't</b> change anything. copy all values/strings
+*/
+struct tag
+{
+ char *name; /**< name of tag */
+ char *value; /**< value of tag */
+ size_t sizeName; /**< size of name in tag */
+ size_t sizeValue; /**< size of value in tag */
+ unsigned long flags; /**< flags of tag */
+};
+
+
+/**
+ object apetag used to store information about tag.
+ main object store **#tag , number of frames, current position for
+ APE_TAG_LIB_NEXT, etc
+ \brief object apetag used to store information about tag
+**/
+typedef struct _ape_mem_cnt apetag;
+
+
+/*
+ * function:
+ * apetag_*: for load/save/init file and structure
+ * apefrm_*: for add del edit one (or more)
+ * frame(, field, entry) in tag
+ */
+
+/* read file and add frames */
+int
+apetag_read (apetag *mem_cnt, char *filename, int flag) ;
+
+/* read file and add frames */
+int
+apetag_read_fp (apetag *mem_cnt, FILE * fp, char *filename, int flag) ;
+
+/* initialise new object #apetag and return */
+apetag *
+apetag_init (void) ;
+
+/* free #apetag object */
+void
+apetag_free (apetag *mem_cnt) ;
+
+/* save apetag to file */
+int
+apetag_save (char *filename, apetag *mem_cnt, int flag) ;
+
+
+/* Add text frame */
+int
+apefrm_add (apetag *mem_cnt, unsigned long flags, char *name, char *value) ;
+
+/* add binary frame */
+int
+apefrm_add_bin (apetag *mem_cnt, unsigned long flags,
+ long sizeName, char *name, long sizeValue, char *value);
+
+/* add frame if other (the same name) no exist */
+int
+apefrm_add_noreplace (apetag *mem_cnt, unsigned long flags, char *name, char *value) ;
+
+/* search in apetag for name and return tag */
+struct tag *
+apefrm_get (apetag *mem_cnt, char *name) ;
+
+/* search in apetag for name and return string */
+char *
+apefrm_getstr (apetag *mem_cnt, char *name) ;
+
+/* remove frame from memory */
+void
+apefrm_remove_real (apetag *mem_cnt, char *name) ;
+
+
+/**
+ \def apefrm_fake_remove(mem_cnt,name)
+ \brief set frame to remove
+ \deprecated remove in 0.5
+*/
+#define apefrm_fake_remove(mem_cnt,name) apefrm_remove(mem_cnt,name)
+
+/* set frame to remove */
+void
+apefrm_remove (apetag *mem_cnt, char *name);
+
+/* read id3v1 and add frames */
+int
+readtag_id3v1_fp (apetag *mem_cnt, FILE * fp) ;
+
+/** \name flags in frames and headers */
+/**\{*/
+//================================
+#define HEADER_IS 0x80000000
+#define HEADER_NOT 0x00000000
+#define HEADER_THIS_IS 0x20000000
+//================================
+#define FOOTER_IS 0x00000000
+#define FOOTER_NOT 0x40000000
+#define FOOTER_THIS_IS 0x00000000
+//================================
+#define ITEM_TEXT 0x00000000
+#define ITEM_BIN 0x00000002
+#define ITEM_LINK 0x00000004
+#define ITEM_URL 0x00000004 // for compability ITEM_LINK
+//================================
+#define TAG_RW 0x00000000
+#define TAG_RO 0x00000001
+/**\}*/
+
+/* debug function print all tags exclude bin (print only size for bin) */
+void
+libapetag_print_mem_cnt (apetag *mem_cnt);
+
+#endif /* _APETAGLIB_H */
diff --git a/src/libapetag/id3v2_read.c b/src/libapetag/id3v2_read.c
new file mode 100755
index 0000000..f4c8a64
--- /dev/null
+++ b/src/libapetag/id3v2_read.c
@@ -0,0 +1,385 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: id3v2_read.c,v 1.16 2003/04/13 11:24:10 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifdef ID3V2_READ
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <math.h>
+#ifndef __BORLANDC__
+# include <unistd.h>
+#endif
+
+#include "apetaglib.h"
+#include <id3.h>
+
+struct id3vtwo2ape {
+ ID3_FrameID frame; //ID3FID_ALBUM etc
+ ID3_FieldID field_type; //ID3FN_TEXT etc
+ const char *APEName;
+ int special; // 0-no 1-???
+};
+
+#define APETAG_TYPE_COMMENT 1
+#define APETAG_TYPE_USER 2
+#define APETAG_TYPE_GENRE 3
+
+
+struct id3vtwo2ape convert[] = {
+ {ID3FID_ALBUM, ID3FN_TEXT, APE_TAG_FIELD_ALBUM,0},
+ {ID3FID_BAND, ID3FN_TEXT, "Band",0},
+ {ID3FID_BPM, ID3FN_TEXT, "BPM",0},
+ {ID3FID_COMPOSER, ID3FN_TEXT, APE_TAG_FIELD_COMPOSER,0},
+ {ID3FID_CONDUCTOR, ID3FN_TEXT, APE_TAG_FIELD_CONDUCTOR,0},
+ {ID3FID_CONTENTGROUP, ID3FN_TEXT, "Content Group",0},
+ {ID3FID_COPYRIGHT, ID3FN_TEXT, APE_TAG_FIELD_COPYRIGHT,0},
+ {ID3FID_DATE, ID3FN_TEXT, APE_TAG_FIELD_RECORDDATE,0},
+ {ID3FID_ENCODEDBY, ID3FN_TEXT, "Encoded By",0},
+ {ID3FID_ENCODERSETTINGS, ID3FN_TEXT, "Encoder",0},
+ {ID3FID_FILEOWNER, ID3FN_TEXT, "File Owner",0},
+ {ID3FID_FILETYPE, ID3FN_TEXT, "File Type",0},
+ {ID3FID_INITIALKEY, ID3FN_TEXT, "Initial Key",0},
+ {ID3FID_ISRC, ID3FN_TEXT, APE_TAG_FIELD_ISRC,0},
+ {ID3FID_LANGUAGE, ID3FN_TEXT, "Language",0},
+ {ID3FID_LEADARTIST, ID3FN_TEXT, APE_TAG_FIELD_ARTIST,0},
+ {ID3FID_LYRICIST, ID3FN_TEXT, "Lyricist",0},
+ {ID3FID_MEDIATYPE, ID3FN_TEXT, APE_TAG_FIELD_MEDIA,0},
+ {ID3FID_MIXARTIST, ID3FN_TEXT, "Mix Artist",0},
+ {ID3FID_NETRADIOOWNER, ID3FN_TEXT, "Internet Radio Owner",0},
+ {ID3FID_NETRADIOSTATION, ID3FN_TEXT, "Internet Radio Station",0},
+ {ID3FID_ORIGALBUM, ID3FN_TEXT, "Original Album",0},
+ {ID3FID_ORIGARTIST, ID3FN_TEXT, "Original Artist",0},
+ {ID3FID_ORIGFILENAME, ID3FN_TEXT, "Original Filename",0},
+ {ID3FID_ORIGLYRICIST, ID3FN_TEXT, "Original Lyricist",0},
+ {ID3FID_ORIGYEAR, ID3FN_TEXT, "Original Artist",0},
+ {ID3FID_PARTINSET, ID3FN_TEXT, "Part",0},
+ {ID3FID_PLAYLISTDELAY, ID3FN_TEXT, "Playlist Delay",0},
+ {ID3FID_PUBLISHER, ID3FN_TEXT, APE_TAG_FIELD_PUBLISHER,0},
+ {ID3FID_RECORDINGDATES, ID3FN_TEXT, APE_TAG_FIELD_RECORDDATE,0},
+ {ID3FID_SIZE, ID3FN_TEXT, "Size",0},
+// {ID3FID_SONGLEN, ID3FN_TEXT, "Song Length",0}, // don't like this in apetag
+ {ID3FID_SUBTITLE, ID3FN_TEXT, APE_TAG_FIELD_SUBTITLE,0},
+ {ID3FID_TIME, ID3FN_TEXT, "Time",0},
+ {ID3FID_TITLE, ID3FN_TEXT, APE_TAG_FIELD_TITLE,0},
+ {ID3FID_TRACKNUM, ID3FN_TEXT, APE_TAG_FIELD_TRACK,0},
+ {ID3FID_YEAR, ID3FN_TEXT, APE_TAG_FIELD_YEAR,0},
+
+ {ID3FID_WWWAUDIOFILE, ID3FN_URL , APE_TAG_FIELD_FILE_URL,0},
+ {ID3FID_WWWARTIST, ID3FN_URL , APE_TAG_FIELD_ARTIST_URL,0},
+ {ID3FID_WWWAUDIOSOURCE, ID3FN_URL , "Source URL",0},
+ {ID3FID_WWWCOMMERCIALINFO, ID3FN_URL , APE_TAG_FIELD_BUY_URL,0},
+ {ID3FID_WWWCOPYRIGHT, ID3FN_URL , APE_TAG_FIELD_COPYRIGHT_URL,0},
+ {ID3FID_WWWPUBLISHER, ID3FN_URL , APE_TAG_FIELD_PUBLISHER_URL,0},
+ {ID3FID_WWWPAYMENT, ID3FN_URL , "Payment",0},
+ {ID3FID_WWWRADIOPAGE, ID3FN_URL , "Web Radio URL",0},
+
+ {ID3FID_COMMENT, ID3FN_TEXT, APE_TAG_FIELD_COMMENT, APETAG_TYPE_COMMENT},
+ {ID3FID_UNSYNCEDLYRICS, ID3FN_TEXT, APE_TAG_FIELD_LYRICS, APETAG_TYPE_COMMENT},
+ {ID3FID_USERTEXT, ID3FN_TEXT, "dummy", APETAG_TYPE_USER},
+ {ID3FID_WWWUSER, ID3FN_URL , APE_TAG_FIELD_RELATED_URL, APETAG_TYPE_USER},
+ {ID3FID_CONTENTTYPE, ID3FN_TEXT, APE_TAG_FIELD_GENRE, APETAG_TYPE_GENRE},
+
+
+
+// {ID3FID_PICTURE, ID3FN_DATA, ,0},
+// {ID3FID_SYNCEDLYRICS, ID3FN_DATA, APE_TAG_FIELD_LYRICS,0},
+// {ID3FID_INVOLVEDPEOPLE, ID3FN_DATA, "Involved People",0}, // type ?
+// {ID3FID_CDID, ID3FN_DATA, "CDID",0}, // ???
+// {ID3FID_TERMSOFUSE, ID3FN_TEXT, "Terms Of Use",0}, // type ?
+};
+
+int
+libapetag_convertID3v2toAPE(const ID3Frame * frame,
+ char **item_, size_t *item_len,
+ char **value_, size_t *value_len,
+ unsigned long *flags);
+
+
+/*
+ use ALOCATE to alocate dynamic memory for frame value
+ this check size of frame and alocate mem and zeroed this mem
+*/
+
+#define ALOCATE(FielD,ValuE,SizeValuE) \
+ SizeValuE = ID3Field_Size(FielD); \
+ ValuE = (SizeValuE!=0) ? (char *) malloc((SizeValuE)+1) : NULL ; \
+ if ((SizeValuE)!=0) ValuE[0] = '\0';
+/*
+ ALOCATE_ITEM its the same ase ALOCATE but for frame name (Item)
+*/
+#define ALOCATE_ITEM(IteM, APENamE, ItemSizE) \
+ ItemSizE = strlen(APENamE) ; \
+ IteM = (ItemSizE!=0) ? (char *) malloc((ItemSizE)+1) : NULL ; \
+ if ((ItemSizE)!=0) IteM[0] = '\0';
+
+int
+libapetag_convertID3v2toAPE (const ID3Frame * frame,
+ char **item_, size_t * item_len,
+ char **value_, size_t * value_len,
+ unsigned long *flags)
+{
+ ID3Field *text;
+ ID3Field *desc;
+ ID3Field *url;
+// ID3Field *bin; // will be implemented some day
+
+ char *item = NULL;
+ char *value = NULL;
+
+ ID3_FrameID frameid = ID3Frame_GetID (frame);
+ unsigned int i;
+
+ *flags = ITEM_TEXT;
+
+ for (i = 0; i < sizeof (convert) / sizeof (struct id3vtwo2ape); i++)
+ if (frameid == convert[i].frame)
+ break;
+
+
+ if (convert[i].field_type == ID3FN_TEXT) {
+ switch (convert[i].special) {
+ case APETAG_TYPE_COMMENT: /* Comments and unsynced lyrics */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ }
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ item[*item_len]='\0';
+ //break;
+ if ((text = ID3Frame_GetField (frame, ID3FN_DESCRIPTION)) != NULL) {
+ char *value_ds=NULL;
+ int value_len2;
+ if (ID3Field_Size(text) != 0) {
+ ALOCATE(text, value_ds, value_len2);
+ ID3Field_GetASCII(text, value_ds, value_len2);
+ if ( strcmp(value_ds, STR_V1_COMMENT_DESC) == 0 ) {
+ value_len2 = 0;
+ value[0]='\0';
+ } else {
+ item = (char *) realloc( item, (*item_len) + value_len2 + 3);
+ item[(*item_len)++]='-'; item[(*item_len)]='\0';
+ strncpy(item + (*item_len),value_ds ,(value_len2 + 1));
+ (*item_len)+=value_len2;
+ }
+ free(value_ds);
+ }
+ }
+ break;
+
+ case APETAG_TYPE_USER: /* User texts */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ }
+ if ((desc = ID3Frame_GetField(frame, ID3FN_DESCRIPTION)) != NULL) {
+ ALOCATE(desc, item, *item_len);
+ ID3Field_GetASCII(desc, item, *item_len);
+ }
+ break;
+
+ case APETAG_TYPE_GENRE: /* genre */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ char *p;
+ int j;
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ value[*value_len]='\0';
+ p = value;
+ if (*p == '(') {
+ p++;
+ while (*p && (*p >= '0' && *p <= '9'))
+ p++;
+ if (*p && *p == ')') {
+ p++;
+ } else {
+ p = value;
+ }
+ *value_len -= (p-value); // corect lenght of frame
+ if (*p != '\0') { // copy in place
+ for (j = 0; *p != '\0'; j++) {
+ value[j] = *p;
+ p++;
+ }
+ value[j] = '\0';
+ }
+ }
+ }
+ break;
+
+ default: /* normal text tags */
+ if ((text = ID3Frame_GetField(frame, ID3FN_TEXT)) != NULL) {
+ ALOCATE(text, value, *value_len);
+ ID3Field_GetASCII(text, value, *value_len);
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ }
+ break;
+
+ } /* <- switch( convert[i].special ) */
+
+ item[*item_len]='\0';
+ value[*value_len]='\0';
+ } else
+ if (convert[i].field_type == ID3FN_URL) {
+ *flags = ITEM_URL;
+ /* TODO: set ape_tag_URL in flag */
+ /* user url */
+ if (convert[i].special == APETAG_TYPE_USER) {
+ if ((url = ID3Frame_GetField(frame, ID3FN_URL)) != NULL) {
+ ALOCATE(url, value, *value_len);
+ ID3Field_GetASCII(url, value, *value_len);
+ }
+ if ((desc = ID3Frame_GetField(frame, ID3FN_DESCRIPTION)) != NULL) {
+ ALOCATE(desc, item, *item_len);
+ ID3Field_GetASCII(desc, item, *item_len);
+ }
+ /* normal url */
+ } else {
+ if ((url = ID3Frame_GetField (frame, ID3FN_URL)) != NULL) {
+ ALOCATE(url, value, *value_len);
+ ID3Field_GetASCII(url, value, *value_len);
+ ALOCATE_ITEM(item, convert[i].APEName, *item_len);
+ strncpy(item, convert[i].APEName, *item_len);
+ }
+ }
+
+ item[*item_len]='\0';
+ value[*value_len]='\0';
+ } else { //convert[i].field_type
+ item = NULL;
+ value = NULL;
+ PRINT_D (">id3v2_read>other\n");
+ }
+ *item_ = item;
+ *value_ = value;
+
+ if (!(value==NULL || (*value_len)==0) && value[(*value_len)-1]=='\0')
+ (*value_len)--;
+
+ return 0;
+}
+
+// Reads ID3v2.x tag
+// idea of this come from "tag" by Case <case@mobiili.net>
+int readtag_id3v2 ( apetag *mem_cnt, char* fileName )
+{
+ ID3Tag* tag;
+ ID3Frame* frame;
+ ID3TagIterator* iter;
+ char* item = NULL;
+ int itemSize;
+ char* value = NULL;
+ int valueSize;
+ unsigned long flags;
+
+ // first - check of id3tag v2 and init
+ if ( (tag = ID3Tag_New ()) == NULL )
+ return 1;
+ // on some casses its weerrryyy slooowwwwlyyy 65k file take 2-5 sec
+ ID3Tag_LinkWithFlags ( tag, fileName, ID3TT_ID3V2 );
+
+ if ( tag == NULL ) {
+ ID3Tag_Delete (tag);
+ return 0;
+ }
+
+ if ( !ID3Tag_HasTagType ( tag, ID3TT_ID3V2 ) ) {
+ ID3Tag_Delete (tag);
+ return 0;
+ }
+
+ if ( (iter = ID3Tag_CreateIterator (tag)) == NULL ) {
+ ID3Tag_Delete (tag);
+ return 0;
+ }
+
+ while ( (frame = ID3TagIterator_GetNext (iter)) != NULL ) {
+
+ libapetag_convertID3v2toAPE ( frame, &item, &itemSize, &value, &valueSize, &flags);
+
+ if ( !item || !value || item[0] == '\0' || value[0] == '\0' )
+ continue;
+
+ if ( !value || value[0] != '\0' ) {
+ PRINT_D4(">id3v2_read>[i%i]%s: [v%i]'%s'\n",itemSize,item,valueSize,value);
+ if ( apefrm_getstr (mem_cnt, item) == NULL ) /* noreplece !!! */
+ apefrm_add_bin (mem_cnt, flags, itemSize, item, valueSize ,value);
+ }
+ free ( value );
+ free ( item );
+ }
+
+ ID3TagIterator_Delete (iter);
+ ID3Tag_Delete (tag);
+
+ return 0;
+}
+
+#endif // ID3V2_READ
+
+
+
+#if 0
+static ID3_FrameDef ID3_FrameDefs[] =
+{
+ /* frames to implement */
+ // short long
+ // frame id id id field defs description
+ {ID3FID_AUDIOCRYPTO, "CRA", "AENC",ID3FD_Unimplemented, "Audio encryption"},
+ {ID3FID_BUFFERSIZE, "BUF", "RBUF",ID3FD_Unimplemented, "Recommended buffer size"},
+ {ID3FID_CDID, "MCI", "MCDI",ID3FD_Unimplemented, "Music CD identifier"},
+ {ID3FID_COMMERCIAL, "" , "COMR",ID3FD_Unimplemented, "Commercial"},
+ {ID3FID_CRYPTOREG, "" , "ENCR",ID3FD_Registration, "Encryption method registration"},
+ {ID3FID_EQUALIZATION, "EQU", "EQUA",ID3FD_Unimplemented, "Equalization"},
+ {ID3FID_EVENTTIMING, "ETC", "ETCO",ID3FD_Unimplemented, "Event timing codes"},
+ {ID3FID_GENERALOBJECT, "GEO", "GEOB",ID3FD_GEO, "General encapsulated object"},
+ {ID3FID_GROUPINGREG, "" , "GRID",ID3FD_Registration, "Group identification registration"},
+ {ID3FID_INVOLVEDPEOPLE, "IPL", "IPLS",ID3FD_InvolvedPeople,"Involved people list"},
+ {ID3FID_LINKEDINFO, "LNK", "LINK",ID3FD_LinkedInfo, "Linked information"},
+ {ID3FID_METACOMPRESSION, "CDM", "" ,ID3FD_CDM, "Compressed data meta frame"},
+ {ID3FID_METACRYPTO, "CRM", "" ,ID3FD_Unimplemented, "Encrypted meta frame"},
+ {ID3FID_MPEGLOOKUP, "MLL", "MLLT",ID3FD_Unimplemented, "MPEG location lookup table"},
+ {ID3FID_OWNERSHIP, "" , "OWNE",ID3FD_Unimplemented, "Ownership frame"},
+ {ID3FID_PICTURE, "PIC", "APIC",ID3FD_Picture, "Attached picture"},
+ {ID3FID_PLAYCOUNTER, "CNT", "PCNT",ID3FD_PlayCounter, "Play counter"},
+ {ID3FID_POPULARIMETER, "POP", "POPM",ID3FD_Popularimeter, "Popularimeter"},
+ {ID3FID_POSITIONSYNC, "" , "POSS",ID3FD_Unimplemented, "Position synchronisation frame"},
+ {ID3FID_PRIVATE, "" , "PRIV",ID3FD_Private, "Private frame"},
+ {ID3FID_REVERB, "REV", "RVRB",ID3FD_Unimplemented, "Reverb"},
+ {ID3FID_SYNCEDLYRICS, "SLT", "SYLT",ID3FD_SyncLyrics, "Synchronized lyric/text"},
+ {ID3FID_SYNCEDTEMPO, "STC", "SYTC",ID3FD_Unimplemented, "Synchronized tempo codes"},
+ {ID3FID_TERMSOFUSE, "" , "USER",ID3FD_TermsOfUse, "Terms of use"},
+ {ID3FID_UNIQUEFILEID, "UFI", "UFID",ID3FD_UFI, "Unique file identifier"},
+ {ID3FID_VOLUMEADJ, "RVA", "RVAD",ID3FD_Unimplemented, "Relative volume adjustment"},
+
+};
+#endif // 0
diff --git a/src/libapetag/id3v2_read.h b/src/libapetag/id3v2_read.h
new file mode 100755
index 0000000..16d433d
--- /dev/null
+++ b/src/libapetag/id3v2_read.h
@@ -0,0 +1,42 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: id3v2_read.h,v 1.6 2003/04/04 20:06:40 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _ID3V2_READ_H
+#define _ID3V2_READ_H
+
+/** \file id3v2_read.h
+ \brief reading id3v2 tag to ape_cnt
+*/
+
+#ifdef ID3V2_READ
+/**
+ reading id3v2 tag to #mem_cnt
+
+ \param mem_cnt stucture ape_mem_cnt
+ \param fileName file name (no file pointer becase libid3 using filename in c mode)
+*/
+int readtag_id3v2 ( apetag *mem_cnt, char* fileName );
+#endif
+
+#endif /* _ID3V2_READ_H */
+
diff --git a/src/libapetag/info_mac.c b/src/libapetag/info_mac.c
new file mode 100755
index 0000000..1b8b5e2
--- /dev/null
+++ b/src/libapetag/info_mac.c
@@ -0,0 +1,151 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: info_mac.c,v 1.15 2003/04/13 11:24:10 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "info_mac.h"
+#include "is_tag.h"
+
+#define MAC_FORMAT_FLAG_8_BIT 1 // 8-bit wave
+#define MAC_FORMAT_FLAG_CRC 2 // new CRC32 error detection
+#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // u-long Peak_Level after the header
+#define MAC_FORMAT_FLAG_24_BIT 8 // 24-bit wave
+#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // number of seek elements after the peak level
+#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // wave header not stored
+
+struct macHeader {
+ char id[4]; // should equal 'MAC '
+ unsigned short ver; // version number * 1000 (3.81 = 3810)
+ unsigned short compLevel; // the compression level
+ unsigned short formatFlags; // any format flags (for future use)
+ unsigned short channels; // the number of channels (1 or 2)
+ unsigned long sampleRate; // the sample rate (typically 44100)
+ unsigned long headerBytesWAV; // the bytes after the MAC header that compose the WAV header
+ unsigned long terminatingBytesWAV; // the bytes after that raw data (for extended info)
+ unsigned long totalFrames; // the number of frames in the file
+ unsigned long finalFrameBlocks; // the number of samples in the final frame
+ unsigned long peakLevel;
+ unsigned short seekElements;
+};
+
+
+// local prototypes
+static int
+monkey_samples_per_frame(unsigned int versionid, unsigned int compressionlevel);
+static const char *
+monkey_stringify(unsigned int profile);
+
+static const char *
+monkey_stringify(unsigned int profile)
+{
+ static const char na[] = "unknown";
+ static const char *Names[] = {
+ na, "Fast", "Normal", "High", "Extra-High", "Insane"
+ };
+ unsigned int profile2 = profile/1000;
+
+ return (profile2 >= sizeof (Names) / sizeof (*Names)) ? na : Names[(profile2)];
+}
+
+
+static int
+monkey_samples_per_frame(unsigned int versionid, unsigned int compressionlevel)
+{
+ if (versionid >= 3950) {
+ return 294912; // 73728 * 4
+ } else if (versionid >= 3900) {
+ return 73728;
+ } else if ((versionid >= 3800) && (compressionlevel == COMPRESSION_LEVEL_EXTRA_HIGH)) {
+ return 73728;
+ } else {
+ return 9216;
+ }
+}
+
+/*
+ return 0; Info has all info
+ return 1; File not found
+ return 2; no MAC file
+*/
+int
+info_mac_read(const char *fn, StreamInfoMac * Info)
+{
+ unsigned int HeaderData[32];
+ FILE *tmpFile = NULL;
+ long SkipSizeID3;
+ struct macHeader * header;
+
+ // load file
+ tmpFile = fopen(fn, "rb");
+
+ if (tmpFile == NULL)
+ return 1; // file not found or read-protected
+
+ // skip id3v2
+ SkipSizeID3 = is_id3v2(tmpFile);
+ fseek(tmpFile, SkipSizeID3, SEEK_SET);
+ fread((void *) HeaderData, sizeof (int), 16, tmpFile);
+ fseek(tmpFile, 0, SEEK_END);
+ Info->FileSize = ftell(tmpFile);
+ fclose(tmpFile);
+
+ if (0 != memcmp(HeaderData, "MAC", 3))
+ return 2; // no monkeyAudio file
+
+ header= (struct macHeader *) HeaderData;
+
+ Info->Version = Info->EncoderVersion = header->ver;
+ Info->Channels = header->channels;
+ Info->SampleFreq = header->sampleRate;
+ Info->Flags = header->formatFlags;
+ Info->SamplesPerFrame = monkey_samples_per_frame(header->ver, header->compLevel);
+ Info->BitsPerSample = (header->formatFlags & MAC_FORMAT_FLAG_8_BIT)
+ ? 8 : ((header->formatFlags & MAC_FORMAT_FLAG_24_BIT) ? 24 : 16);
+
+ Info->PeakLevel = header->peakLevel;
+// Info->PeakRatio = Info->PakLevel / pow(2, Info->bitsPerSample - 1);
+ Info->Frames = header->totalFrames;
+ Info->Samples = (Info->Frames - 1) * Info->SamplesPerFrame +
+ header->finalFrameBlocks;
+
+ Info->Duration = Info->SampleFreq > 0 ?
+ ((float)Info->Samples / Info->SampleFreq)*1000 : 0;
+
+ Info->Compresion = header->compLevel;
+ Info->CompresionName = monkey_stringify(Info->Compresion);
+
+ Info->UncompresedSize = Info->Samples * Info->Channels *
+ (Info->BitsPerSample / 8);
+
+ Info->CompresionRatio =
+ (Info->UncompresedSize + header->headerBytesWAV) > 0 ?
+ Info->FileSize / (float) (Info->UncompresedSize +
+ header->headerBytesWAV) : 0. ;
+
+ Info->Bitrate = Info->Duration > 0 ? (((Info->Samples *
+ Info->Channels * Info->BitsPerSample) / (float) Info->Duration) *
+ Info->CompresionRatio) * 1000 : 0;
+
+ Info->PeakRatio=Info->ByteLength=0;
+ return 0;
+}
diff --git a/src/libapetag/info_mac.h b/src/libapetag/info_mac.h
new file mode 100755
index 0000000..a17e47c
--- /dev/null
+++ b/src/libapetag/info_mac.h
@@ -0,0 +1,96 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: info_mac.h,v 1.6 2003/04/13 11:24:10 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef INFO_MAC_H
+#define INFO_MAC_H
+
+/** \file info_mac.h
+ \brief Get information from MonkeyAudio file.
+
+ Usage:
+ \code
+ StreamInfoMac Info;
+
+ if (info_mac_read(fn, &Info)) {
+ printf("File \"%s\" not found or is read protected!\n", fn);
+ return;
+ }
+ printf("%",Info.fields...);
+ \endcode
+*/
+
+/**
+ \name Compression level
+*/
+/*\{*/
+#define COMPRESSION_LEVEL_FAST 1000 /**< fast */
+#define COMPRESSION_LEVEL_NORMAL 2000 /**< optimal average time/compression ratio */
+#define COMPRESSION_LEVEL_HIGH 3000 /**< higher compression ratio */
+#define COMPRESSION_LEVEL_EXTRA_HIGH 4000 /**< very slowly */
+#define COMPRESSION_LEVEL_INSANE 5000 /**< ??? */
+/*\}*/
+
+/** All information from mac file
+ * \struct StreamInfoMac
+**/
+typedef struct
+{
+ unsigned int ByteLength; /**< file length - tags size */
+ unsigned int FileSize; /**< real file size */
+ int SampleFreq; /**< sample frequency */
+ unsigned int Channels; /**< number of chanels */
+ int Duration; /**< duratiom in ms */
+
+ unsigned int Version; /**< version of current file */
+ unsigned int Bitrate; /**< bitrate of current file (bps) */
+ unsigned int Compresion; /**< compresion profile */
+ unsigned int Flags; /**< flags */
+
+ unsigned int Frames; /**< number of frames */
+ unsigned int SamplesPerFrame; /**< samples per frame */
+ unsigned int Samples; /**< number of samples */
+ unsigned int BitsPerSample; /**< bits per sample */
+ unsigned int UncompresedSize; /**< uncomprese size of file */
+ float CompresionRatio; /**< compresion ratio */
+
+ unsigned int PeakLevel; /**< peak level */
+ float PeakRatio; /**< peak ratio */
+
+ const char *CompresionName; /**< compresion profile as string */
+
+ unsigned int EncoderVersion; /**< version of encoder used */
+} StreamInfoMac;
+
+/**
+ Read all mac info from filename
+
+ \param fn File name
+ \param Info StreamInfoMac Structure for all information
+ \retval 0 ok
+ \retval 1 file not found or write protected
+ \retval 2 not monkey's audio file
+*/
+int
+info_mac_read(const char *fn, StreamInfoMac * Info);
+
+#endif /* INFO_MAC_H */
diff --git a/src/libapetag/info_mpc.c b/src/libapetag/info_mpc.c
new file mode 100755
index 0000000..18ee71b
--- /dev/null
+++ b/src/libapetag/info_mpc.c
@@ -0,0 +1,198 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: info_mpc.c,v 1.12 2003/04/13 11:24:10 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ Some portions of code or/and ideas come from
+ winamp plugins, xmms plugins, mppdec decoder
+ thanks:
+ -Frank Klemm <Frank.Klemm@uni-jena.de>
+ -Andree Buschmann <Andree.Buschmann@web.de>
+ -Thomas Juerges <thomas.juerges@astro.ruhr-uni-bochum.de>
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "info_mpc.h"
+#include "is_tag.h"
+
+
+/*
+*.MPC,*.MP+,*.MPP
+*/
+static const char *
+profile_stringify(unsigned int profile); // profile is 0...15, where 7...13 is used
+
+
+static const char *
+profile_stringify(unsigned int profile) // profile is 0...15, where 7...13 is used
+{
+ static const char na[] = "n.a.";
+ static const char *Names[] = {
+ na, "Experimental", na, na,
+ na, na, na, "Telephone",
+ "Thumb", "Radio", "Standard", "Xtreme",
+ "Insane", "BrainDead", "BrainDead+", "BrainDead++"
+ };
+
+ return profile >=
+ sizeof (Names) / sizeof (*Names) ? na : Names[profile];
+}
+
+int
+read_file_header_fp(FILE *fp, StreamInfoMpc * Info)
+{
+
+return 0;
+}
+
+/*
+ return 0; Info has all info
+ return 1; File not found
+ return 2; no Mpc file
+*/
+int
+info_mpc_read(const char *fn, StreamInfoMpc * Info)
+{
+ unsigned int HeaderData[16];
+ FILE *tmpFile = NULL;
+ long SkipSizeID3;
+
+ // load file
+ tmpFile = fopen(fn, "rb");
+
+ if (tmpFile == NULL)
+ return 1; // file not found or read-protected
+ // skip id3v2
+ SkipSizeID3=is_id3v2(tmpFile);
+ fseek(tmpFile,SkipSizeID3 , SEEK_SET);
+ fread((void *) HeaderData, sizeof (int), 16, tmpFile);
+ fseek(tmpFile, 0, SEEK_END);
+ Info->FileSize=ftell(tmpFile);
+ // stream size
+ Info->ByteLength = Info->FileSize-is_id3v1(tmpFile)-is_ape(tmpFile)-SkipSizeID3;
+
+ fclose(tmpFile);
+
+ if (0 != memcmp(HeaderData, "MP+", 3))
+ return 2; // no musepack file
+
+ Info->StreamVersion = HeaderData[0] >> 24;
+ if (Info->StreamVersion >= 7) {
+ const long samplefreqs[4] = { 44100, 48000, 37800, 32000 };
+
+ // read the file-header (SV7 and above)
+ Info->Bitrate = 0;
+ Info->Frames = HeaderData[1];
+ Info->SampleFreq = samplefreqs[(HeaderData[2] >> 16) & 0x0003];
+ Info->MaxBand = (HeaderData[2] >> 24) & 0x003F;
+ Info->MS = (HeaderData[2] >> 30) & 0x0001;
+ Info->Profile = (HeaderData[2] << 8) >> 28;
+ Info->IS = (HeaderData[2] >> 31) & 0x0001;
+ Info->BlockSize = 1;
+
+ Info->EncoderVersion = (HeaderData[6] >> 24) & 0x00FF;
+ Info->Channels = 2;
+ // gain
+ Info->EstPeakTitle = HeaderData[2] & 0xFFFF; // read the ReplayGain data
+ Info->GainTitle = (HeaderData[3] >> 16) & 0xFFFF;
+ Info->PeakTitle = HeaderData[3] & 0xFFFF;
+ Info->GainAlbum = (HeaderData[4] >> 16) & 0xFFFF;
+ Info->PeakAlbum = HeaderData[4] & 0xFFFF;
+ // gaples
+ Info->IsTrueGapless = (HeaderData[5] >> 31) & 0x0001; // true gapless: used?
+ Info->LastFrameSamples = (HeaderData[5] >> 20) & 0x07FF; // true gapless: valid samples for last frame
+
+ if (Info->EncoderVersion == 0) {
+ sprintf(Info->Encoder, "<= 1.05"); // Buschmann 1.7.x, Klemm <= 1.05
+ } else {
+ switch (Info->EncoderVersion % 10) {
+ case 0:
+ sprintf(Info->Encoder, "%u.%u",
+ Info->EncoderVersion / 100,
+ Info->EncoderVersion / 10 % 10);
+ break;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ sprintf(Info->Encoder, "%u.%02u Beta",
+ Info->EncoderVersion / 100,
+ Info->EncoderVersion % 100);
+ break;
+ default:
+ sprintf(Info->Encoder, "%u.%02u Alpha",
+ Info->EncoderVersion / 100,
+ Info->EncoderVersion % 100);
+ break;
+ }
+ }
+ // estimation, exact value needs too much time
+ Info->Bitrate = (long) (Info->ByteLength) * 8. * Info->SampleFreq / (1152 * Info->Frames - 576);
+
+ } else {
+ // read the file-header (SV6 and below)
+ Info->Bitrate = ((HeaderData[0] >> 23) & 0x01FF) * 1000; // read the file-header (SV6 and below)
+ Info->MS = (HeaderData[0] >> 21) & 0x0001;
+ Info->IS = (HeaderData[0] >> 22) & 0x0001;
+ Info->StreamVersion = (HeaderData[0] >> 11) & 0x03FF;
+ Info->MaxBand = (HeaderData[0] >> 6) & 0x001F;
+ Info->BlockSize = (HeaderData[0]) & 0x003F;
+
+ Info->Profile = 0;
+ //gain
+ Info->GainTitle = 0; // not supported
+ Info->PeakTitle = 0;
+ Info->GainAlbum = 0;
+ Info->PeakAlbum = 0;
+ //gaples
+ Info->LastFrameSamples = 0;
+ Info->IsTrueGapless = 0;
+
+ if (Info->StreamVersion >= 5)
+ Info->Frames = HeaderData[1]; // 32 bit
+ else
+ Info->Frames = (HeaderData[1] >> 16); // 16 bit
+
+ Info->EncoderVersion = 0;
+ Info->Encoder[0] = '\0';
+#if 0
+ if (Info->StreamVersion == 7)
+ return ERROR_CODE_SV7BETA; // are there any unsupported parameters used?
+ if (Info->Bitrate != 0)
+ return ERROR_CODE_CBR;
+ if (Info->IS != 0)
+ return ERROR_CODE_IS;
+ if (Info->BlockSize != 1)
+ return ERROR_CODE_BLOCKSIZE;
+#endif
+ if (Info->StreamVersion < 6) // Bugfix: last frame was invalid for up to SV5
+ Info->Frames -= 1;
+
+ Info->SampleFreq = 44100; // AB: used by all files up to SV7
+ Info->Channels = 2;
+ }
+
+ Info->ProfileName=profile_stringify(Info->Profile);
+
+ Info->Duration = (int) (Info->Frames * 1152 / (Info->SampleFreq/1000.0));
+ return 0;
+}
diff --git a/src/libapetag/info_mpc.h b/src/libapetag/info_mpc.h
new file mode 100755
index 0000000..330cbf0
--- /dev/null
+++ b/src/libapetag/info_mpc.h
@@ -0,0 +1,96 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: info_mpc.h,v 1.8 2003/04/13 11:24:10 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef INFO_MPC_H
+#define INFO_MPC_H
+
+/** \file info_mpc.h
+ \brief Get information from MusePack file.
+
+ Usage:
+ \code
+ StreamInfoMpc Info;
+
+ if (info_mpc_read(fn, &Info)) {
+ printf("File \"%s\" not found or is read protected!\n", fn);
+ return;
+ }
+ printf("%",Info.fields);
+ \endcode
+*/
+
+
+/** All information from mpc file
+ * \struct StreamInfoMpc
+**/
+typedef struct
+{
+ unsigned int ByteLength; /**< file length - tags size */
+ unsigned int FileSize; /**< real file size */
+ int SampleFreq; /**< Sample frequency */
+ unsigned int Channels; /**< channels =2 */
+ int Duration; /**< duratiom in ms */
+
+ unsigned int StreamVersion; /**< Streamversion of current file */
+ unsigned int Bitrate; /**< bitrate of current file (bps) */
+ unsigned int Frames; /**< number of frames contained */
+ unsigned int MS; /**< Mid/Side Stereo (0: off, 1: on) */
+ unsigned int Profile; /**< quality profile */
+ unsigned int MaxBand; /**< maximum band-index used (0...31) */
+ unsigned int IS; /**< Intensity Stereo (0: off, 1: on) */
+ unsigned int BlockSize; /**< only needed for SV4...SV6 -> not supported */
+
+ const char *ProfileName; /**< Profile name */
+ unsigned int EncoderVersion; /**< version of encoder used */
+ char Encoder[256]; /**< Encoder Version in string */
+
+ // ReplayGain related data
+ short GainTitle; /**< Gain Title */
+ short GainAlbum; /**< Gain Album */
+ unsigned short PeakAlbum; /**< Peak value of Album */
+ unsigned short PeakTitle; /**< Peak value of Title */
+ unsigned short EstPeakTitle; /**< Estimated Peak value of Title */
+
+ // true gapless stuff
+ unsigned int IsTrueGapless; /**< is true gapless used? */
+ unsigned int LastFrameSamples; /**< number of valid samples within last frame */
+} StreamInfoMpc;
+
+/** \def StreamInfo is only for compatible before 0.4alpha4
+ \deprecated removed in 0.5
+*/
+#define StreamInfo StreamInfoMpc
+
+/**
+ Read all mpc info from filename
+
+ \param fn File name
+ \param Info StreamInfoMpc Structure for all information
+ \retval 0 ok
+ \retval 1 file not found or write protected
+ \retval 2 not musepack audio file
+*/
+int
+info_mpc_read(const char *fn, StreamInfoMpc *Info);
+
+#endif /* INFO_MPC_H */
diff --git a/src/libapetag/is_tag.c b/src/libapetag/is_tag.c
new file mode 100755
index 0000000..dc56023
--- /dev/null
+++ b/src/libapetag/is_tag.c
@@ -0,0 +1,175 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: is_tag.c,v 1.10 2003/04/16 21:06:27 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include "is_tag.h"
+
+unsigned long
+is_tag_ape2long (unsigned char *p);
+
+/*
+ PL: czy dany plik ma taga odpowiednio id3v1, id3v2 i ape ???
+ PL: nie zmienia pozycji w pliku !!!
+*/
+
+/**
+ return size of all id3v1 tags (some bugy tagers add this again and
+ again tag) 0 no tag at all
+
+ \param fp File pointer
+ \return Return size of id3v1 tag (in bytes) 0 no tag at all
+*/
+int
+is_id3v1 (FILE * fp)
+{
+ int n=0;
+ char buf[16];
+ size_t savedFilePosition;
+
+ savedFilePosition = ftell (fp);
+ fseek (fp, 0, SEEK_END);
+ do {
+ n++;
+ memset (buf, 0, sizeof (buf));
+ fseek (fp, ((-128)*n) - 3 , SEEK_END);
+ fread (&buf, 1, sizeof (buf), fp);
+ if (memcmp (buf, "APETAGEX",8) == 0) /*APE.TAG.EX*/
+ break;
+ } while (memcmp (buf+3, "TAG", 3) == 0);
+
+ fseek (fp, savedFilePosition, SEEK_SET);
+ return (n-1)*128;
+}
+
+/**
+ return size of tag id3v2 on begining of file.
+ check for buggy tagers (2 or more tags)
+
+ \param fp File pointer
+ \return Return size of id3v2 tag (in bytes)
+ (some bugy tagers add this again and again ) 0 no tag at all
+*/
+int
+is_id3v2 (FILE * fp)
+{
+ char buf[16];
+ size_t savedFilePosition;
+ long id3v2size=0;
+
+ savedFilePosition = ftell (fp);
+ fseek (fp, 0, SEEK_SET);
+ do {
+ memset (buf, 0, sizeof (buf));
+ fseek (fp, id3v2size, SEEK_SET);
+ fread (&buf, 1, sizeof (buf), fp);
+ if (memcmp (buf, "ID3", 3) != 0) {
+ break;
+ }
+ /* ID3v2 tag skipeer $49 44 33 yy yy xx zz zz zz zz [zz size + this 10 bytes] */
+ id3v2size += 10 + (((long) (buf[9])) | ((long) (buf[8]) << 7) |
+ ((long) (buf[7]) << 14) | ((long) (buf[6]) << 21));
+ } while(memcmp (buf, "ID3", 3) == 0);
+
+ fseek (fp, savedFilePosition, SEEK_SET);
+ return (int) id3v2size;
+}
+
+
+/**
+ return 0 or 1000 or 2000 this is version of ape tag 0 no tag
+
+ \param fp File pointer
+ \return Version of ape tag if any, else 0
+*/
+int
+is_ape_ver (FILE * fp)
+{
+ char unsigned buf[32];
+ size_t savedFilePosition;
+
+ savedFilePosition = ftell (fp);
+ memset (buf, 0, sizeof (buf));
+
+ fseek (fp, (is_id3v1 (fp) ? -32 - 128 : -32), SEEK_END);
+ fread (&buf, 1, sizeof (buf), fp);
+ if (memcmp (buf, "APETAGEX", 8) != 0) {
+ fseek (fp, savedFilePosition, SEEK_SET);
+ return 0;
+ }
+
+ fseek (fp, savedFilePosition, SEEK_SET);
+ return (int) is_tag_ape2long (buf + 8);
+}
+
+#define IS_TAG_FOOTER_NOT 0x40000000
+
+/**
+ return size of ape tag id3v1 is not counting
+
+ \param fp File pointer
+ \return Size of ape tag if any, else 0
+*/
+int
+is_ape (FILE * fp)
+{
+ char unsigned buf[32];
+ size_t savedFilePosition;
+
+ savedFilePosition = ftell (fp);
+ memset (buf, 0, sizeof (buf));
+
+ fseek (fp, (is_id3v1 (fp) ? -32 - 128 : -32), SEEK_END);
+ fread (&buf, 1, sizeof (buf), fp);
+ if (memcmp (buf, "APETAGEX", 8) != 0) {
+ fseek (fp, savedFilePosition, SEEK_SET);
+ return 0;
+ }
+
+ fseek (fp, savedFilePosition, SEEK_SET);
+ /* WARNING! macabra code */
+ return (int) (is_tag_ape2long (buf + 8 + 4) +
+ (
+ ( (is_tag_ape2long (buf + 8) == 2000) &&
+ !(is_tag_ape2long (buf + 8 + 4 + 8) & IS_TAG_FOOTER_NOT)
+ ) ? 32 : 0
+ ) /* footer size = 32 */
+ );
+}
+
+
+unsigned long
+is_tag_ape2long (unsigned char *p)
+{
+
+ return (((unsigned long) p[0] << 0) |
+ ((unsigned long) p[1] << 8) |
+ ((unsigned long) p[2] << 16) |
+ ((unsigned long) p[3] << 24) );
+
+}
diff --git a/src/libapetag/is_tag.h b/src/libapetag/is_tag.h
new file mode 100755
index 0000000..bb04061
--- /dev/null
+++ b/src/libapetag/is_tag.h
@@ -0,0 +1,41 @@
+/********************************************************************
+*
+* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved.
+* <artii@o2.pl> LGPL-2.1
+* $ArtId: is_tag.h,v 1.7 2003/04/13 11:24:10 art Exp $
+********************************************************************/
+/*
+ * This program 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.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _IS_TAG_H
+#define _IS_TAG_H
+
+/** \file is_tag.h
+ \brief Function for check if tag is avilable
+
+ All is_* function restore file positon on return
+*/
+
+int is_id3v1 (FILE * fp);
+
+int is_id3v2 (FILE * fp);
+
+int is_ape (FILE * fp);
+
+int is_ape_ver (FILE * fp);
+
+#endif /* _IS_TAG_H */