From ba15707b292d827bdce732e7713b26fae3f75c74 Mon Sep 17 00:00:00 2001 From: Alex Bennee Date: Wed, 14 Jul 2010 15:57:06 +0100 Subject: EasyTag 2.1.1 --- src/libapetag/COPYING.LGPL | 510 +++++++++++++++++++++ src/libapetag/Makefile.am | 22 + src/libapetag/Makefile.in | 471 +++++++++++++++++++ src/libapetag/README.apetag | 12 + src/libapetag/apetaglib.c | 1065 +++++++++++++++++++++++++++++++++++++++++++ src/libapetag/apetaglib.h | 277 +++++++++++ src/libapetag/id3v2_read.c | 385 ++++++++++++++++ src/libapetag/id3v2_read.h | 42 ++ src/libapetag/info_mac.c | 151 ++++++ src/libapetag/info_mac.h | 96 ++++ src/libapetag/info_mpc.c | 198 ++++++++ src/libapetag/info_mpc.h | 96 ++++ src/libapetag/is_tag.c | 175 +++++++ src/libapetag/is_tag.h | 41 ++ 14 files changed, 3541 insertions(+) create mode 100755 src/libapetag/COPYING.LGPL create mode 100755 src/libapetag/Makefile.am create mode 100644 src/libapetag/Makefile.in create mode 100755 src/libapetag/README.apetag create mode 100755 src/libapetag/apetaglib.c create mode 100755 src/libapetag/apetaglib.h create mode 100755 src/libapetag/id3v2_read.c create mode 100755 src/libapetag/id3v2_read.h create mode 100755 src/libapetag/info_mac.c create mode 100755 src/libapetag/info_mac.h create mode 100755 src/libapetag/info_mpc.c create mode 100755 src/libapetag/info_mpc.h create mode 100755 src/libapetag/is_tag.c create mode 100755 src/libapetag/is_tag.h (limited to 'src/libapetag') 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. + + + + Copyright (C) + + 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. + + , 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 o2 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. +* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef __BORLANDC__ +# include +#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 +#include +#include +/* 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. +* 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 don't 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. +* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef __BORLANDC__ +# include +#endif + +#include "apetaglib.h" +#include + +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 +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. +* 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. +* 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 +#include +#include +#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. +* 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. +* 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 + -Andree Buschmann + -Thomas Juerges +*/ + +#include +#include +#include +#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. +* 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. +* 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 +#include +#include +#include +#include +#include +#include +#include +#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. +* 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 */ -- cgit v1.2.3