diff --git a/Libraries/TagLib/English.lproj/InfoPlist.strings b/Libraries/TagLib/English.lproj/InfoPlist.strings new file mode 100644 index 000000000..7080cf949 Binary files /dev/null and b/Libraries/TagLib/English.lproj/InfoPlist.strings differ diff --git a/Libraries/TagLib/Files/AUTHORS b/Libraries/TagLib/Files/AUTHORS new file mode 100644 index 000000000..463ed20f3 --- /dev/null +++ b/Libraries/TagLib/Files/AUTHORS @@ -0,0 +1,8 @@ +Scott Wheeler + Author, maintainer +Ismael Orenstein + Xing header implementation +Allan Sandfeld Jensen + FLAC metadata implementation +Teemu Tervo + Numerous bug reports and fixes diff --git a/Libraries/TagLib/Files/COPYING b/Libraries/TagLib/Files/COPYING new file mode 100644 index 000000000..e38ffa837 --- /dev/null +++ b/Libraries/TagLib/Files/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 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. + + 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. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + 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 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/Libraries/TagLib/Files/ChangeLog b/Libraries/TagLib/Files/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/Libraries/TagLib/Files/INSTALL b/Libraries/TagLib/Files/INSTALL new file mode 100644 index 000000000..02a4a0740 --- /dev/null +++ b/Libraries/TagLib/Files/INSTALL @@ -0,0 +1,167 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Type `make install' to install the programs and any data files and + documentation. + + 4. You can remove the program binaries and object files from the + source code directory by typing `make clean'. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Libraries/TagLib/Files/Makefile.am b/Libraries/TagLib/Files/Makefile.am new file mode 100644 index 000000000..1c1f9be51 --- /dev/null +++ b/Libraries/TagLib/Files/Makefile.am @@ -0,0 +1,29 @@ +SUBDIRS = taglib bindings tests + +EXTRA_DIST = admin AUTHORS COPYING ChangeLog INSTALL README TODO taglib.lsm + +AUTOMAKE_OPTIONS = foreign + +$(top_srcdir)/configure.in: configure.in.in $(top_srcdir)/subdirs + cd $(top_srcdir) && $(MAKE) -f admin/Makefile.common configure.in ; + +$(top_srcdir)/subdirs: + cd $(top_srcdir) && $(MAKE) -f admin/Makefile.common subdirs + +$(top_srcdir)/acinclude.m4: $(top_srcdir)/admin/acinclude.m4.in $(top_srcdir)/admin/libtool.m4.in + @cd $(top_srcdir) && cat admin/acinclude.m4.in admin/libtool.m4.in > acinclude.m4 + +MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 configure.files + +package-messages: + $(MAKE) -f admin/Makefile.common package-messages + +dist-hook: + cd $(top_distdir) && perl admin/am_edit -padmin + cd $(top_distdir) && $(MAKE) -f admin/Makefile.common subdirs + +examples: examples-all + +examples-all: + cd examples ; \ + $(MAKE) all diff --git a/Libraries/TagLib/Files/Makefile.cvs b/Libraries/TagLib/Files/Makefile.cvs new file mode 100644 index 000000000..ac8066e05 --- /dev/null +++ b/Libraries/TagLib/Files/Makefile.cvs @@ -0,0 +1,14 @@ +all: + @echo "This Makefile is only for the CVS repository" + @echo "This will be deleted before making the distribution" + @echo "" + @if test ! -d admin; then \ + echo "Please recheckout this module!" ;\ + echo "for cvs: use checkout once and after that update again" ;\ + echo "for cvsup: checkout kde-common from cvsup and" ;\ + echo " link kde-common/admin to ./admin" ;\ + exit 1 ;\ + fi + $(MAKE) -f admin/Makefile.common cvs + +.SILENT: diff --git a/Libraries/TagLib/Files/Makefile.in b/Libraries/TagLib/Files/Makefile.in new file mode 100644 index 000000000..7801b37b1 --- /dev/null +++ b/Libraries/TagLib/Files/Makefile.in @@ -0,0 +1,643 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +SUBDIRS = taglib bindings tests + +EXTRA_DIST = admin AUTHORS COPYING ChangeLog INSTALL README TODO taglib.lsm + +AUTOMAKE_OPTIONS = foreign + +MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 configure.files +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = + +RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ + ps-recursive install-info-recursive uninstall-info-recursive \ + all-recursive install-data-recursive install-exec-recursive \ + installdirs-recursive install-recursive uninstall-recursive \ + check-recursive installcheck-recursive +DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ + Makefile.in TODO acinclude.m4 aclocal.m4 admin/ChangeLog \ + admin/compile admin/config.guess admin/config.sub admin/depcomp \ + admin/install-sh admin/ltmain.sh admin/missing \ + admin/mkinstalldirs admin/ylwrap config.h.in configure \ + configure.in +DIST_SUBDIRS = $(SUBDIRS) +#>- all: config.h +#>+ 1 +all: docs-am config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: + +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --foreign Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile + cd $(top_srcdir) && perl admin/am_edit Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) + +$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +$(ACLOCAL_M4): configure.in acinclude.m4 + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h + +$(srcdir)/config.h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOHEADER) + touch $(srcdir)/config.h.in + +distclean-hdr: + -rm -f config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(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 +#>- DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +#>+ 4 +KDE_DIST=configure.files configure.in.in Makefile.cvs subdirs + +DISTFILES= $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) $(KDE_DIST) + + +top_distdir = . +distdir = $(PACKAGE)-$(VERSION) + +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } + +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkinstalldirs) $(distdir)/admin $(distdir)/taglib + @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"; \ + $(mkinstalldirs) "$(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 + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist dist-all: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + $(am__remove_distdir) + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && $(mkinstalldirs) "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ + && rm -f $(distdir).tar.gz \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @echo "$(distdir).tar.gz is ready for distribution" | \ + sed 'h;s/./=/g;p;x;p;x' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +#>- clean: clean-recursive +#>+ 1 +clean: kde-rpo-clean clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) +distclean-am: clean-am distclean-generic distclean-hdr distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ + clean-generic clean-libtool clean-recursive ctags \ + ctags-recursive dist dist-all dist-gzip distcheck distclean \ + distclean-generic distclean-hdr distclean-libtool \ + distclean-recursive distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am dvi-recursive info info-am \ + info-recursive install install-am install-data install-data-am \ + install-data-recursive install-exec install-exec-am \ + install-exec-recursive install-info install-info-am \ + install-info-recursive install-man install-recursive \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am installdirs-recursive maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive mostlyclean \ + mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ + pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ + tags-recursive uninstall uninstall-am uninstall-info-am \ + uninstall-info-recursive uninstall-recursive + + +$(top_srcdir)/configure.in: configure.in.in $(top_srcdir)/subdirs + cd $(top_srcdir) && $(MAKE) -f admin/Makefile.common configure.in ; + +$(top_srcdir)/subdirs: + cd $(top_srcdir) && $(MAKE) -f admin/Makefile.common subdirs + +$(top_srcdir)/acinclude.m4: $(top_srcdir)/admin/acinclude.m4.in $(top_srcdir)/admin/libtool.m4.in + @cd $(top_srcdir) && cat admin/acinclude.m4.in admin/libtool.m4.in > acinclude.m4 + +package-messages: + $(MAKE) -f admin/Makefile.common package-messages + +dist-hook: + cd $(top_distdir) && perl admin/am_edit -padmin + cd $(top_distdir) && $(MAKE) -f admin/Makefile.common subdirs + +examples: examples-all + +examples-all: + cd examples ; \ + $(MAKE) all +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile + cd $(top_srcdir) && perl admin/am_edit Makefile.in + + +#>+ 2 +final: + $(MAKE) all-am +#>+ 2 +final-install: + $(MAKE) install-am +#>+ 2 +no-final: + $(MAKE) all-am +#>+ 2 +no-final-install: + $(MAKE) install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/README b/Libraries/TagLib/Files/README new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Libraries/TagLib/Files/README @@ -0,0 +1 @@ + diff --git a/Libraries/TagLib/Files/TODO b/Libraries/TagLib/Files/TODO new file mode 100644 index 000000000..e69de29bb diff --git a/Libraries/TagLib/Files/bindings/c/tag_c.cpp b/Libraries/TagLib/Files/bindings/c/tag_c.cpp new file mode 100644 index 000000000..f13348167 --- /dev/null +++ b/Libraries/TagLib/Files/bindings/c/tag_c.cpp @@ -0,0 +1,237 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "tag_c.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace TagLib +{ + static List strings; + static bool unicodeStrings = true; + static bool stringManagementEnabled = true; +} + +using namespace TagLib; + +void taglib_set_strings_unicode(BOOL unicode) +{ + unicodeStrings = bool(unicode); +} + +void taglib_set_string_management_enabled(BOOL management) +{ + stringManagementEnabled = bool(management); +} + +//////////////////////////////////////////////////////////////////////////////// +// TagLib::File wrapper +//////////////////////////////////////////////////////////////////////////////// + +TagLib_File *taglib_file_new(const char *filename) +{ + return reinterpret_cast(FileRef::create(filename)); +} + +TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type) +{ + switch(type) { + case TagLib_File_MPEG: + return reinterpret_cast(new MPEG::File(filename)); + case TagLib_File_OggVorbis: + return reinterpret_cast(new Vorbis::File(filename)); + case TagLib_File_FLAC: + return reinterpret_cast(new FLAC::File(filename)); + case TagLib_File_MPC: + return reinterpret_cast(new MPC::File(filename)); + } + + return 0; +} + +void taglib_file_free(TagLib_File *file) +{ + delete reinterpret_cast(file); +} + +TagLib_Tag *taglib_file_tag(const TagLib_File *file) +{ + const File *f = reinterpret_cast(file); + return reinterpret_cast(f->tag()); +} + +const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file) +{ + const File *f = reinterpret_cast(file); + return reinterpret_cast(f->audioProperties()); +} + +BOOL taglib_file_save(TagLib_File *file) +{ + return reinterpret_cast(file)->save(); +} + +//////////////////////////////////////////////////////////////////////////////// +// TagLib::Tag wrapper +//////////////////////////////////////////////////////////////////////////////// + +char *taglib_tag_title(const TagLib_Tag *tag) +{ + const Tag *t = reinterpret_cast(tag); + char *s = ::strdup(t->title().toCString(unicodeStrings)); + if(stringManagementEnabled) + strings.append(s); + return s; +} + +char *taglib_tag_artist(const TagLib_Tag *tag) +{ + const Tag *t = reinterpret_cast(tag); + char *s = ::strdup(t->artist().toCString(unicodeStrings)); + if(stringManagementEnabled) + strings.append(s); + return s; +} + +char *taglib_tag_album(const TagLib_Tag *tag) +{ + const Tag *t = reinterpret_cast(tag); + char *s = ::strdup(t->album().toCString(unicodeStrings)); + if(stringManagementEnabled) + strings.append(s); + return s; +} + +char *taglib_tag_comment(const TagLib_Tag *tag) +{ + const Tag *t = reinterpret_cast(tag); + char *s = ::strdup(t->comment().toCString(unicodeStrings)); + if(stringManagementEnabled) + strings.append(s); + return s; +} + +char *taglib_tag_genre(const TagLib_Tag *tag) +{ + const Tag *t = reinterpret_cast(tag); + char *s = ::strdup(t->genre().toCString(unicodeStrings)); + if(stringManagementEnabled) + strings.append(s); + return s; +} + +unsigned int taglib_tag_year(const TagLib_Tag *tag) +{ + const Tag *t = reinterpret_cast(tag); + return t->year(); +} + +unsigned int taglib_tag_track(const TagLib_Tag *tag) +{ + const Tag *t = reinterpret_cast(tag); + return t->track(); +} + +void taglib_tag_set_title(TagLib_Tag *tag, const char *title) +{ + Tag *t = reinterpret_cast(tag); + t->setTitle(String(title, unicodeStrings ? String::UTF8 : String::Latin1)); +} + +void taglib_tag_set_artist(TagLib_Tag *tag, const char *artist) +{ + Tag *t = reinterpret_cast(tag); + t->setArtist(String(artist, unicodeStrings ? String::UTF8 : String::Latin1)); +} + +void taglib_tag_set_album(TagLib_Tag *tag, const char *album) +{ + Tag *t = reinterpret_cast(tag); + t->setAlbum(String(album, unicodeStrings ? String::UTF8 : String::Latin1)); +} + +void taglib_tag_set_comment(TagLib_Tag *tag, const char *comment) +{ + Tag *t = reinterpret_cast(tag); + t->setComment(String(comment, unicodeStrings ? String::UTF8 : String::Latin1)); +} + +void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre) +{ + Tag *t = reinterpret_cast(tag); + t->setGenre(String(genre, unicodeStrings ? String::UTF8 : String::Latin1)); +} + +void taglib_tag_set_year(TagLib_Tag *tag, unsigned int year) +{ + Tag *t = reinterpret_cast(tag); + t->setYear(year); +} + +void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track) +{ + Tag *t = reinterpret_cast(tag); + t->setTrack(track); +} + +void taglib_tag_free_strings() +{ + if(!stringManagementEnabled) + return; + + for(List::Iterator it = strings.begin(); it != strings.end(); ++it) + delete [] *it; + strings.clear(); +} + +//////////////////////////////////////////////////////////////////////////////// +// TagLib::AudioProperties wrapper +//////////////////////////////////////////////////////////////////////////////// + +int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties) +{ + const AudioProperties *p = reinterpret_cast(audioProperties); + return p->length(); +} + +int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties) +{ + const AudioProperties *p = reinterpret_cast(audioProperties); + return p->bitrate(); +} + +int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties) +{ + const AudioProperties *p = reinterpret_cast(audioProperties); + return p->sampleRate(); +} + +int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties) +{ + const AudioProperties *p = reinterpret_cast(audioProperties); + return p->channels(); +} diff --git a/Libraries/TagLib/Files/bindings/c/tag_c.h b/Libraries/TagLib/Files/bindings/c/tag_c.h new file mode 100644 index 000000000..ea042489c --- /dev/null +++ b/Libraries/TagLib/Files/bindings/c/tag_c.h @@ -0,0 +1,250 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_TAG_C +#define TAGLIB_TAG_C + +/* Do not include this in the main TagLib documentation. */ +#ifndef DO_NOT_DOCUMENT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef BOOL +#define BOOL int +#endif + +/******************************************************************************* + * [ TagLib C Binding ] + * + * This is an interface to TagLib's "simple" API, meaning that you can read and + * modify media files in a generic, but not specialized way. This is a rough + * representation of TagLib::File and TagLib::Tag, for which the documentation + * is somewhat more complete and worth consulting. + *******************************************************************************/ + +/* + * These are used for type provide some type safety to the C API (as opposed to + * using void *, but pointers to them are simply cast to the coresponding C++ + * types in the implementation. + */ + +typedef struct { int dummy; } TagLib_File; +typedef struct { int dummy; } TagLib_Tag; +typedef struct { int dummy; } TagLib_AudioProperties; + +/*! + * By default all strings coming into or out of TagLib's C API are in UTF8. + * However, it may be desirable for TagLib to operate on Latin1 (ISO-8859-1) + * strings in which case this should be set to FALSE. + */ +void taglib_set_strings_unicode(BOOL unicode); + +/*! + * TagLib can keep track of strings that are created when outputting tag values + * and clear them using taglib_tag_clear_strings(). This is enabled by default. + * However if you wish to do more fine grained management of strings, you can do + * so by setting \a management to FALSE. + */ +void taglib_set_string_management_enabled(BOOL management); + +/******************************************************************************* + * File API + ******************************************************************************/ + +typedef enum { + TagLib_File_MPEG, + TagLib_File_OggVorbis, + TagLib_File_FLAC, + TagLib_File_MPC +} TagLib_File_Type; + +/*! + * Creates a TagLib file based on \a filename. TagLib will try to guess the file + * type. + * + * \returns NULL if the file type cannot be determined or the file cannot + * be opened. + */ +TagLib_File *taglib_file_new(const char *filename); + +/*! + * Creates a TagLib file based on \a filename. Rather than attempting to guess + * the type, it will use the one specified by \a type. + */ +TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type); + +/*! + * Frees and closes the file. + */ +void taglib_file_free(TagLib_File *file); + +/*! + * Returns a pointer to the tag associated with this file. This will be freed + * automatically when the file is freed. + */ +TagLib_Tag *taglib_file_tag(const TagLib_File *file); + +/*! + * Returns a pointer to the the audio properties associated with this file. This + * will be freed automatically when the file is freed. + */ +const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file); + +/*! + * Saves the \a file to disk. + */ +BOOL taglib_file_save(TagLib_File *file); + +/****************************************************************************** + * Tag API + ******************************************************************************/ + +/*! + * Returns a string with this tag's title. + * + * \note By default this string should be UTF8 encoded and its memory should be + * freed using taglib_tag_free_strings(). + */ +char *taglib_tag_title(const TagLib_Tag *tag); + +/*! + * Returns a string with this tag's artist. + * + * \note By default this string should be UTF8 encoded and its memory should be + * freed using taglib_tag_free_strings(). + */ +char *taglib_tag_artist(const TagLib_Tag *tag); + +/*! + * Returns a string with this tag's album name. + * + * \note By default this string should be UTF8 encoded and its memory should be + * freed using taglib_tag_free_strings(). + */ +char *taglib_tag_album(const TagLib_Tag *tag); + +/*! + * Returns a string with this tag's comment. + * + * \note By default this string should be UTF8 encoded and its memory should be + * freed using taglib_tag_free_strings(). + */ +char *taglib_tag_comment(const TagLib_Tag *tag); + +/*! + * Returns a string with this tag's genre. + * + * \note By default this string should be UTF8 encoded and its memory should be + * freed using taglib_tag_free_strings(). + */ +char *taglib_tag_genre(const TagLib_Tag *tag); + +/*! + * Returns the tag's year or 0 if year is not set. + */ +unsigned int taglib_tag_year(const TagLib_Tag *tag); + +/*! + * Returns the tag's track number or 0 if track number is not set. + */ +unsigned int taglib_tag_track(const TagLib_Tag *tag); + +/*! + * Sets the tag's title. + * + * \note By default this string should be UTF8 encoded. + */ +void taglib_tag_set_title(TagLib_Tag *tag, const char *title); + +/*! + * Sets the tag's artist. + * + * \note By default this string should be UTF8 encoded. + */ +void taglib_tag_set_artist(TagLib_Tag *tag, const char *artist); + +/*! + * Sets the tag's album. + * + * \note By default this string should be UTF8 encoded. + */ +void taglib_tag_set_album(TagLib_Tag *tag, const char *album); + +/*! + * Sets the tag's comment. + * + * \note By default this string should be UTF8 encoded. + */ +void taglib_tag_set_comment(TagLib_Tag *tag, const char *comment); + +/*! + * Sets the tag's genre. + * + * \note By default this string should be UTF8 encoded. + */ +void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre); + +/*! + * Sets the tag's year. 0 indicates that this field should be cleared. + */ +void taglib_tag_set_year(TagLib_Tag *tag, unsigned int year); + +/*! + * Sets the tag's track number. 0 indicates that this field should be cleared. + */ +void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track); + +/*! + * Frees all of the strings that have been created by the tag. + */ +void taglib_tag_free_strings(); + +/****************************************************************************** + * Audio Properties API + ******************************************************************************/ + +/*! + * Returns the lenght of the file in seconds. + */ +int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties); + +/*! + * Returns the bitrate of the file in kb/s. + */ +int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties); + +/*! + * Returns the sample rate of the file in Hz. + */ +int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties); + +/*! + * Returns the number of channels in the audio stream. + */ +int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties); + +#ifdef __cplusplus +} +#endif +#endif /* DO_NOT_DOCUMENT */ +#endif diff --git a/Libraries/TagLib/Files/config.h b/Libraries/TagLib/Files/config.h new file mode 100644 index 000000000..1df8d2bb0 --- /dev/null +++ b/Libraries/TagLib/Files/config.h @@ -0,0 +1,65 @@ +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* C++ compiler supports template repository */ +#define HAVE_TEMPLATE_REPOSITORY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* have zlib */ +#define HAVE_ZLIB 0 + +/* Suffix for lib directories */ +#define KDELIBSUFF "" + +/* Name of package */ +#define PACKAGE "taglib" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.1" diff --git a/Libraries/TagLib/Files/taglib/ape/Makefile.am b/Libraries/TagLib/Files/taglib/ape/Makefile.am new file mode 100644 index 000000000..6d0635a7f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + $(all_includes) + +noinst_LTLIBRARIES = libape.la + +libape_la_SOURCES = apetag.cpp apefooter.cpp apeitem.cpp + +taglib_include_HEADERS = apetag.h apefooter.h apeitem.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libape_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/ape/Makefile.in b/Libraries/TagLib/Files/taglib/ape/Makefile.in new file mode 100644 index 000000000..acc1357d6 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/Makefile.in @@ -0,0 +1,553 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + $(all_includes) + + +noinst_LTLIBRARIES = libape.la + +libape_la_SOURCES = apetag.cpp apefooter.cpp apeitem.cpp + +taglib_include_HEADERS = apetag.h apefooter.h apeitem.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libape_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/ape +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libape_la_LDFLAGS = +libape_la_LIBADD = +am_libape_la_OBJECTS = apetag.lo apefooter.lo apeitem.lo +#>- libape_la_OBJECTS = $(am_libape_la_OBJECTS) +#>+ 4 +libape_la_final_OBJECTS = libape_la.all_cpp.lo +libape_la_nofinal_OBJECTS = apetag.lo apefooter.lo apeitem.lo +@KDE_USE_FINAL_FALSE@libape_la_OBJECTS = $(libape_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libape_la_OBJECTS = $(libape_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/apefooter.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/apeitem.Plo ./$(DEPDIR)/apetag.Plo +#>+ 5 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libape_la.all_cpp.P ./$(DEPDIR)/apefooter.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/apeitem.Plo ./$(DEPDIR)/apetag.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/apefooter.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/apeitem.Plo ./$(DEPDIR)/apetag.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libape_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(libape_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/ape/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ape/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ape/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libape.la: $(libape_la_OBJECTS) $(libape_la_DEPENDENCIES) + $(CXXLINK) $(libape_la_LDFLAGS) $(libape_la_OBJECTS) $(libape_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apefooter.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apeitem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apetag.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +#>- DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +#>+ 4 +KDE_DIST=ape-tag-format.txt + +DISTFILES= $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) $(KDE_DIST) + + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ape/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ape/Makefile.in + + +#>+ 11 +libape_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/apetag.cpp $(srcdir)/apefooter.cpp $(srcdir)/apeitem.cpp + @echo 'creating libape_la.all_cpp.cpp ...'; \ + rm -f libape_la.all_cpp.files libape_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libape_la.all_cpp.final; \ + for file in apetag.cpp apefooter.cpp apeitem.cpp ; do \ + echo "#include \"$$file\"" >> libape_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libape_la.all_cpp.final; \ + done; \ + cat libape_la.all_cpp.final libape_la.all_cpp.files > libape_la.all_cpp.cpp; \ + rm -f libape_la.all_cpp.final libape_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libape_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libape_la_OBJECTS="$(libape_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libape_la_OBJECTS="$(libape_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libape_la_OBJECTS="$(libape_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libape_la_OBJECTS="$(libape_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/ape/ape-tag-format.txt b/Libraries/TagLib/Files/taglib/ape/ape-tag-format.txt new file mode 100644 index 000000000..21ff1c861 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/ape-tag-format.txt @@ -0,0 +1,170 @@ +================================================================================ += APE Tag Specification, Version 2.000 +================================================================================ + +Original Content (C) 2004, Frank Klemm +Formatting / Editing (C) 2004, Scott Wheeler + +================================================================================ += Contents +================================================================================ + +1 - APE Tag General Structure +2 - APE Tag Header / Footer Format +3 - APE Tag Flags +4 - APE Tag Item Format +5 - APE Tag Item Supported Keys +6 - APE Tag Item Content +7 - Data Types +7.1 - Data Types / UTF-8 +7.2 - Data Types / Dates +7.3 - Data Types / Timestamps + +================================================================================ += 1 - APE Tag General Structure +================================================================================ + +Member of Basic Components of SV8 Stream Note: + +It is strongly recommended that the data size be stored in the tags. The size +should normally be in the roughly one kilobyte, never more than 8 kilobytes. + +Larger data should be stored externally using link entries. Linked data is much +easier to process by normal programs, so for instance JPEG data should not be +included inside the audio file. + +APE Tag Version 2.000 (with header, recommended): + +/================================\ +| APE Tag Header | 32 bytes | +|-------------------|------------| +| APE Tag Item 1 | > 10 bytes | +| APE Tag Item 2 | > 10 bytes | +| APE Tag Item n-1 | > 10 bytes | +| APE Tag Item n | > 10 bytes | +|-------------------|------------| +| APE Tag Footer | 32 bytes | +\================================/ + + +APE tag items should be sorted ascending by size. When streaming, parts of the +APE tag may be dropped to reduce the danger of drop outs between tracks. This +is not required, but is strongly recommended. It would be desirable for the i +tems to be sorted by importance / size, but this is not feasible. This +convention should only be broken when adding less important small items and it +is not desirable to rewrite the entire tag. An APE tag at the end of a file +(the recommended location) must have at least a footer; an APE tag at the +beginning of a file (strongly discouraged) must have at least a header. + +APE Tag Version 1.000 (without header, deprecated) + +/================================\ +| APE Tag Item 1 | > 10 bytes | +| APE Tag Item 2 | > 10 bytes | +| APE Tag Item n-1 | > 10 bytes | +| APE Tag Item n | > 10 bytes | +|-------------------|------------| +| APE Tag Footer | 32 bytes | +\================================/ + +================================================================================ += 2 - APE Tag Header / Footer Format +================================================================================ + +Contains number, length and attributes of all tag items + +Header and Footer are different in 1 bit in the Tags Flags to distinguish +between them. + +Member of APE Tag 2.0 + +/===========================================================================\ +| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } | +|----------------|---------|------------------------------------------------| +| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 | +|----------------|---------|------------------------------------------------| +| Tag Size | 4 bytes | Tag size in bytes including footer and all tag | +| | | items excluding the header (for 1.000 | +| | | compatibility) | +|----------------|---------|------------------------------------------------| +| Item Count | 4 bytes | Number of items in the tag | +|----------------|---------|------------------------------------------------| +| Tag Flags | 4 bytes | Global flags | +|----------------|---------|------------------------------------------------| +| Reserved | 8 bytes | Must be zeroed | +\===========================================================================/ + +================================================================================ += 3 - APE Tag Flags +================================================================================ + +The general flag structure for either items or headers / footers is the same. +Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are +item specific. + +Note: APE Tags from Version 1.0 do not use any of the following. All flags in +that version are zeroed and ignored when reading. + +/=================================================================\ +| Contains Header | Bit 31 | 1 - has header | 0 - no header | +|-----------------|-------------|---------------------------------| +| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer | +|-----------------|-------------|---------------------------------| +| Is Header | Bit 29 | 1 - is header | 0 - is footer | +|-----------------|-------------|---------------------------------| +| Undefined | Bits 28 - 3 | Undefined, must be zeroed | +|-----------------|-------------|---------------------------------| +| Encoding | Bits 2 - 1 | 00 - UTF-8 | +| | | 01 - Binary Data * | +| | | 10 - External Reference ** | +| | | 11 - Reserved | +|-----------------|-------------|---------------------------------| +| Read Only | Bit 0 | 1 - read only | 0 - read/write | +\=================================================================/ + + (*) Should be ignored by tools for editing text values +(**) Allowed external reference formats: + - http://host/directory/filename.ext + - ftp://host/directory/filename.ext + - filename.ext + - /directory/filename.ext + - DRIVE:/directory/filename.ext + + Note: External references are also UTF-8 encoded. + +================================================================================ += 4 - APE Tag Item Format +================================================================================ + +APE Tag Items are stored as key-value pairs. APE Tags Item Key are case +sensitive, however it is illegal to use keys which only differ in case and +it is recommended that tag reading not be case sensitive. + +Every key can only occur (at most) once. It is not possible to repeat a key +to signify updated contents. + +Tags can be partially or completely repeated in the streaming format. This +makes it possible to display an artist and / or title if it was missed at the +beginning of the stream. It is recommended that the important information like +artist, album and title should occur approximately every 2 minutes in the +stream and again 5 to 10 seconds before the end. However, care should be tak +en not to replicate this information too often or during passages with high +bitrate demands to avoid unnecessary drop-outs. + +/==============================================================================\ +| Content Size | 4 bytes | Length of the value in bytes | +|----------------|---------------|---------------------------------------------| +| Flags | 4 bytes | Item flags | +|----------------|---------------|---------------------------------------------| +| Key | 2 - 255 bytes | Item key | +|----------------|---------------|---------------------------------------------| +| Key Terminator | 1 byte | Null byte that indicates the end of the key | +|----------------|---------------|---------------------------------------------| +| Value | variable | Content (formatted according to the flags) | +\==============================================================================/ + +================================================================================ + +Sections 5 - 7 haven't yet been converted from: + +http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html diff --git a/Libraries/TagLib/Files/taglib/ape/apefooter.cpp b/Libraries/TagLib/Files/taglib/ape/apefooter.cpp new file mode 100644 index 000000000..5fc8c2602 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/apefooter.cpp @@ -0,0 +1,232 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + (C) 2002, 2003 by Scott Wheeler (id3v2header.cpp) + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include +#include + +#include "apefooter.h" + +using namespace TagLib; +using namespace APE; + +class Footer::FooterPrivate +{ +public: + FooterPrivate() : version(0), + footerPresent(true), + headerPresent(false), + isHeader(false), + itemCount(0), + tagSize(0) {} + + ~FooterPrivate() {} + + uint version; + + bool footerPresent; + bool headerPresent; + + bool isHeader; + + uint itemCount; + uint tagSize; + + static const uint size = 32; +}; + +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +TagLib::uint Footer::size() +{ + return FooterPrivate::size; +} + +ByteVector Footer::fileIdentifier() +{ + return ByteVector::fromCString("APETAGEX"); +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Footer::Footer() +{ + d = new FooterPrivate; +} + +Footer::Footer(const ByteVector &data) +{ + d = new FooterPrivate; + parse(data); +} + +Footer::~Footer() +{ + delete d; +} + +TagLib::uint Footer::version() const +{ + return d->version; +} + +bool Footer::headerPresent() const +{ + return d->headerPresent; +} + +bool Footer::footerPresent() const +{ + return d->footerPresent; +} + +bool Footer::isHeader() const +{ + return d->isHeader; +} + +void Footer::setHeaderPresent(bool b) const +{ + d->headerPresent = b; +} + +TagLib::uint Footer::itemCount() const +{ + return d->itemCount; +} + +void Footer::setItemCount(uint s) +{ + d->itemCount = s; +} + +TagLib::uint Footer::tagSize() const +{ + return d->tagSize; +} + +TagLib::uint Footer::completeTagSize() const +{ + if(d->headerPresent) + return d->tagSize + d->size; + else + return d->tagSize; +} + +void Footer::setTagSize(uint s) +{ + d->tagSize = s; +} + +void Footer::setData(const ByteVector &data) +{ + parse(data); +} + +ByteVector Footer::renderFooter() const +{ + return render(false); +} + +ByteVector Footer::renderHeader() const +{ + if (!d->headerPresent) return ByteVector(); + + return render(true); +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void Footer::parse(const ByteVector &data) +{ + if(data.size() < size()) + return; + + // The first eight bytes, data[0..7], are the File Identifier, "APETAGEX". + + // Read the version number + + d->version = data.mid(8, 4).toUInt(false); + + // Read the tag size + + d->tagSize = data.mid(12, 4).toUInt(false); + + // Read the item count + + d->itemCount = data.mid(16, 4).toUInt(false); + + // Read the flags + + std::bitset<32> flags(data.mid(20, 4).toUInt(false)); + + d->headerPresent = flags[31]; + d->footerPresent = !flags[30]; + d->isHeader = flags[29]; + +} + +ByteVector Footer::render(bool isHeader) const +{ + ByteVector v; + + // add the file identifier -- "APETAGEX" + + v.append(fileIdentifier()); + + // add the version number -- we always render a 2.000 tag regardless of what + // the tag originally was. + + v.append(ByteVector::fromUInt(2000, false)); + + // add the tag size + + v.append(ByteVector::fromUInt(d->tagSize, false)); + + // add the item count + + v.append(ByteVector::fromUInt(d->itemCount, false)); + + // render and add the flags + + std::bitset<32> flags; + + flags[31] = d->headerPresent; + flags[30] = false; // footer is always present + flags[29] = isHeader; + + v.append(ByteVector::fromUInt(flags.to_ulong(), false)); + + // add the reserved 64bit + + v.append(ByteVector::fromLongLong(0)); + + return v; +} diff --git a/Libraries/TagLib/Files/taglib/ape/apefooter.h b/Libraries/TagLib/Files/taglib/ape/apefooter.h new file mode 100644 index 000000000..b3359d13f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/apefooter.h @@ -0,0 +1,168 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_APEFOOTER_H +#define TAGLIB_APEFOOTER_H + +#include + +namespace TagLib { + + namespace APE { + + //! An implementation of APE footers + + /*! + * This class implements APE footers (and headers). It attempts to follow, both + * semantically and programatically, the structure specified in + * the APE v2.0 standard. The API is based on the properties of APE footer and + * headers specified there. + */ + + class Footer + { + public: + /*! + * Constructs an empty APE footer. + */ + Footer(); + + /*! + * Constructs an APE footer based on \a data. parse() is called + * immediately. + */ + Footer(const ByteVector &data); + + /*! + * Destroys the footer. + */ + virtual ~Footer(); + + /*! + * Returns the version number. (Note: This is the 1000 or 2000.) + */ + uint version() const; + + /*! + * Returns true if a header is present in the tag. + */ + bool headerPresent() const; + + /*! + * Returns true if a footer is present in the tag. + */ + bool footerPresent() const; + + /*! + * Returns true this is actually the header. + */ + bool isHeader() const; + + /*! + * Sets whether the header should be rendered or not + */ + void setHeaderPresent(bool b) const; + + /*! + * Returns the number of items in the tag. + */ + uint itemCount() const; + + /*! + * Set the item count to \a s. + * \see itemCount() + */ + void setItemCount(uint s); + + /*! + * Returns the tag size in bytes. This is the size of the frame content and footer. + * The size of the \e entire tag will be this plus the header size, if present. + * + * \see completeTagSize() + */ + uint tagSize() const; + + /*! + * Returns the tag size, including if present, the header + * size. + * + * \see tagSize() + */ + uint completeTagSize() const; + + /*! + * Set the tag size to \a s. + * \see tagSize() + */ + void setTagSize(uint s); + + /*! + * Returns the size of the footer. Presently this is always 32 bytes. + */ + static uint size(); + + /*! + * Returns the string used to identify an APE tag inside of a file. + * Presently this is always "APETAGEX". + */ + static ByteVector fileIdentifier(); + + /*! + * Sets the data that will be used as the footer. 32 bytes, + * starting from \a data will be used. + */ + void setData(const ByteVector &data); + + /*! + * Renders the footer back to binary format. + */ + ByteVector renderFooter() const; + + /*! + * Renders the header corresponding to the footer. If headerPresent is + * set to false, it returns an empty ByteVector. + */ + ByteVector renderHeader() const; + + protected: + /*! + * Called by setData() to parse the footer data. It makes this information + * available through the public API. + */ + void parse(const ByteVector &data); + + /*! + * Called by renderFooter and renderHeader + */ + ByteVector render(bool isHeader) const; + + private: + Footer(const Footer &); + Footer &operator=(const Footer &); + + class FooterPrivate; + FooterPrivate *d; + }; + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/ape/apeitem.cpp b/Libraries/TagLib/Files/taglib/ape/apeitem.cpp new file mode 100644 index 000000000..a211220b4 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/apeitem.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include "apeitem.h" + +using namespace TagLib; +using namespace APE; + +class APE::Item::ItemPrivate +{ +public: + ItemPrivate() : type(Text), readOnly(false) {} + + Item::ItemTypes type; + String key; + ByteVector value; + StringList text; + bool readOnly; +}; + +APE::Item::Item() +{ + d = new ItemPrivate; +} + +APE::Item::Item(const String &key, const String &value) +{ + d = new ItemPrivate; + d->key = key; + d->text.append(value); +} + +APE::Item::Item(const String &key, const StringList &values) +{ + d = new ItemPrivate; + d->key = key; + d->text = values; +} + +APE::Item::Item(const Item &item) +{ + d = new ItemPrivate(*item.d); +} + +Item &APE::Item::operator=(const Item &item) +{ + delete d; + d = new ItemPrivate(*item.d); + return *this; +} + +void APE::Item::setReadOnly(bool readOnly) +{ + d->readOnly = readOnly; +} + +bool APE::Item::isReadOnly() const +{ + return d->readOnly; +} + +void APE::Item::setType(APE::Item::ItemTypes val) +{ + d->type = val; +} + +APE::Item::ItemTypes APE::Item::type() const +{ + return d->type; +} + +String APE::Item::key() const +{ + return d->key; +} + +ByteVector APE::Item::value() const +{ + return d->value; +} + +int APE::Item::size() const +{ + return 8 + d->key.size() + 1 + d->value.size(); +} + +StringList APE::Item::toStringList() const +{ + return d->text; +} + +String APE::Item::toString() const +{ + return d->text.front(); +} + +bool APE::Item::isEmpty() const +{ + switch(d->type) { + case 0: + case 1: + if(d->text.isEmpty()) + return true; + if(d->text.size() == 1 && d->text.front() == "") + return true; + return false; + case 2: + return d->value.isEmpty(); + default: + return false; + } +} + +void APE::Item::parse(const ByteVector &data) +{ + // 11 bytes is the minimum size for an APE item + + if(data.size() < 11) { + debug("APE::Item::parse() -- no data in item"); + return; + } + + uint valueLength = data.mid(0, 4).toUInt(false); + uint flags = data.mid(4, 4).toUInt(false); + + d->key = String(data.mid(8), String::UTF8); + + d->value = data.mid(8 + d->key.size() + 1, valueLength); + + setReadOnly(flags & 1); + setType(ItemTypes((flags >> 1) & 3)); + + if(int(d->type) < 2) + d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8); +} + +ByteVector APE::Item::render() const +{ + ByteVector data; + TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); + ByteVector value; + + if(isEmpty()) + return data; + + if(d->type != Item::Binary) { + StringList::ConstIterator it = d->text.begin(); + value.append(it->data(String::UTF8)); + it++; + for(; it != d->text.end(); ++it) { + value.append('\0'); + value.append(it->data(String::UTF8)); + } + d->value = value; + } + else + value.append(d->value); + + data.append(ByteVector::fromUInt(value.size(), false)); + data.append(ByteVector::fromUInt(flags, false)); + data.append(d->key.data(String::UTF8)); + data.append(ByteVector('\0')); + data.append(value); + + return data; +} diff --git a/Libraries/TagLib/Files/taglib/ape/apeitem.h b/Libraries/TagLib/Files/taglib/ape/apeitem.h new file mode 100644 index 000000000..f0a1d16ab --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/apeitem.h @@ -0,0 +1,150 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_APEITEM_H +#define TAGLIB_APEITEM_H + +#include +#include +#include + +namespace TagLib { + + namespace APE { + + //! An implementation of APE-items + + /*! + * This class provides the features of items in the APEv2 standard. + */ + class Item + { + public: + /*! + * Enum of types an Item can have. The value of 3 is reserved. + */ + enum ItemTypes { + //! Item contains text information coded in UTF-8 + Text = 0, + //! Item contains binary information + Binary = 1, + //! Item is a locator of external stored information + Locator = 2 + }; + /*! + * Constructs an empty item. + */ + Item(); + + /*! + * Constructs an item with \a key and \a value. + */ + Item(const String &key, const String &value); + + /*! + * Constructs an item with \a key and \a values. + */ + Item(const String &key, const StringList &values); + + /*! + * Construct an item as a copy of \a item. + */ + Item(const Item &item); + + /*! + * Copies the contents of \a item into this item. + */ + Item &operator=(const Item &item); + + /*! + * Returns the key. + */ + String key() const; + + /*! + * Returns the binary value. + */ + ByteVector value() const; + + /*! + * Returns the size of the full item. + */ + int size() const; + + /*! + * Returns the value as a single string. In case of multiple strings, + * the first is returned. + */ + String toString() const; + + /*! + * Returns the value as a string list. + */ + StringList toStringList() const; + + /*! + * Render the item to a ByteVector. + */ + ByteVector render() const; + + /*! + * Parse the item from the ByteVector \a data. + */ + void parse(const ByteVector& data); + + /*! + * Set the item to read-only. + */ + void setReadOnly(bool readOnly); + + /*! + * Return true if the item is read-only. + */ + bool isReadOnly() const; + + /*! + * Sets the type of the item to \a type. + * + * \see ItemTypes + */ + void setType(ItemTypes type); + + /*! + * Returns the type of the item. + */ + ItemTypes type() const; + + /*! + * Returns if the item has any real content. + */ + bool isEmpty() const; + + private: + class ItemPrivate; + ItemPrivate *d; + }; + } + +} + +#endif + + diff --git a/Libraries/TagLib/Files/taglib/ape/apetag.cpp b/Libraries/TagLib/Files/taglib/ape/apetag.cpp new file mode 100644 index 000000000..3fecad8ba --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/apetag.cpp @@ -0,0 +1,255 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.com + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "apetag.h" +#include "apefooter.h" +#include "apeitem.h" + +using namespace TagLib; +using namespace APE; + +class APE::Tag::TagPrivate +{ +public: + TagPrivate() : file(0), tagOffset(-1), tagLength(0) {} + + File *file; + long tagOffset; + long tagLength; + + Footer footer; + + ItemListMap itemListMap; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public methods +//////////////////////////////////////////////////////////////////////////////// + +APE::Tag::Tag() : TagLib::Tag() +{ + d = new TagPrivate; +} + +APE::Tag::Tag(File *file, long tagOffset) : TagLib::Tag() +{ + d = new TagPrivate; + d->file = file; + d->tagOffset = tagOffset; + + read(); +} + +APE::Tag::~Tag() +{ + delete d; +} + +ByteVector APE::Tag::fileIdentifier() +{ + return ByteVector::fromCString("APETAGEX"); +} + +String APE::Tag::title() const +{ + if(d->itemListMap["TITLE"].isEmpty()) + return String::null; + return d->itemListMap["TITLE"].toString(); +} + +String APE::Tag::artist() const +{ + if(d->itemListMap["ARTIST"].isEmpty()) + return String::null; + return d->itemListMap["ARTIST"].toString(); +} + +String APE::Tag::album() const +{ + if(d->itemListMap["ALBUM"].isEmpty()) + return String::null; + return d->itemListMap["ALBUM"].toString(); +} + +String APE::Tag::comment() const +{ + if(d->itemListMap["COMMENT"].isEmpty()) + return String::null; + return d->itemListMap["COMMENT"].toString(); +} + +String APE::Tag::genre() const +{ + if(d->itemListMap["GENRE"].isEmpty()) + return String::null; + return d->itemListMap["GENRE"].toString(); +} + +TagLib::uint APE::Tag::year() const +{ + if(d->itemListMap["YEAR"].isEmpty()) + return 0; + return d->itemListMap["YEAR"].toString().toInt(); +} + +TagLib::uint APE::Tag::track() const +{ + if(d->itemListMap["TRACK"].isEmpty()) + return 0; + return d->itemListMap["TRACK"].toString().toInt(); +} + +void APE::Tag::setTitle(const String &s) +{ + addValue("TITLE", s, true); +} + +void APE::Tag::setArtist(const String &s) +{ + addValue("ARTIST", s, true); +} + +void APE::Tag::setAlbum(const String &s) +{ + addValue("ALBUM", s, true); +} + +void APE::Tag::setComment(const String &s) +{ + addValue("COMMENT", s, true); +} + +void APE::Tag::setGenre(const String &s) +{ + addValue("GENRE", s, true); +} + +void APE::Tag::setYear(uint i) +{ + if(i <= 0) + removeItem("YEAR"); + else + addValue("YEAR", String::number(i), true); +} + +void APE::Tag::setTrack(uint i) +{ + if(i <= 0) + removeItem("TRACK"); + else + addValue("TRACK", String::number(i), true); +} + +APE::Footer *APE::Tag::footer() const +{ + return &d->footer; +} + +const APE::ItemListMap& APE::Tag::itemListMap() const +{ + return d->itemListMap; +} + +void APE::Tag::removeItem(const String &key) +{ + Map::Iterator it = d->itemListMap.find(key.upper()); + if(it != d->itemListMap.end()) + d->itemListMap.erase(it); +} + +void APE::Tag::addValue(const String &key, const String &value, bool replace) +{ + if(replace) + removeItem(key); + if(!value.isEmpty()) { + if(d->itemListMap.contains(key) || !replace) + d->itemListMap[key.upper()].toStringList().append(value); + else + setItem(key, Item(key, value)); + } +} + +void APE::Tag::setItem(const String &key, const Item &item) +{ + d->itemListMap.insert(key.upper(), item); +} + +//////////////////////////////////////////////////////////////////////////////// +// protected methods +//////////////////////////////////////////////////////////////////////////////// + +void APE::Tag::read() +{ + if(d->file && d->file->isValid()) { + + d->file->seek(d->tagOffset); + d->footer.setData(d->file->readBlock(Footer::size())); + + if(d->footer.tagSize() == 0 || + d->footer.tagSize() > uint(d->file->length())) + return; + + d->file->seek(d->tagOffset + Footer::size() - d->footer.tagSize()); + parse(d->file->readBlock(d->footer.tagSize() - Footer::size())); + } +} + +ByteVector APE::Tag::render() const +{ + ByteVector data; + uint itemCount = 0; + + { + for(Map::ConstIterator it = d->itemListMap.begin(); + it != d->itemListMap.end(); ++it) + { + data.append(it->second.render()); + itemCount++; + } + } + + d->footer.setItemCount(itemCount); + d->footer.setTagSize(data.size()+Footer::size()); + d->footer.setHeaderPresent(true); + + return d->footer.renderHeader() + data + d->footer.renderFooter(); +} + +void APE::Tag::parse(const ByteVector &data) +{ + uint pos = 0; + + // 11 bytes is the minimum size for an APE item + + for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) { + APE::Item item; + item.parse(data.mid(pos)); + + d->itemListMap.insert(item.key().upper(), item); + + pos += item.size(); + } +} diff --git a/Libraries/TagLib/Files/taglib/ape/apetag.h b/Libraries/TagLib/Files/taglib/ape/apetag.h new file mode 100644 index 000000000..b06f1e254 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ape/apetag.h @@ -0,0 +1,157 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_APETAG_H +#define TAGLIB_APETAG_H + +#include +#include +#include +#include + +#include "apeitem.h" + +namespace TagLib { + + class File; + + //! An implementation of the APE tagging format + + namespace APE { + + class Footer; + + /*! + * A mapping between a list of item names, or keys, and the associated item. + * + * \see APE::Tag::itemListMap() + */ + typedef Map ItemListMap; + + + //! An APE tag implementation + + class Tag : public TagLib::Tag + { + public: + /*! + * Create an APE tag with default values. + */ + Tag(); + + /*! + * Create an APE tag and parse the data in \a file with APE footer at + * \a tagOffset. + */ + Tag(File *file, long tagOffset); + + /*! + * Destroys this Tag instance. + */ + virtual ~Tag(); + + /*! + * Renders the in memory values to a ByteVector suitable for writing to + * the file. + */ + ByteVector render() const; + + /*! + * Returns the string "APETAGEX" suitable for usage in locating the tag in a + * file. + */ + static ByteVector fileIdentifier(); + + // Reimplementations. + + virtual String title() const; + virtual String artist() const; + virtual String album() const; + virtual String comment() const; + virtual String genre() const; + virtual uint year() const; + virtual uint track() const; + + virtual void setTitle(const String &s); + virtual void setArtist(const String &s); + virtual void setAlbum(const String &s); + virtual void setComment(const String &s); + virtual void setGenre(const String &s); + virtual void setYear(uint i); + virtual void setTrack(uint i); + + /*! + * Returns a pointer to the tag's footer. + */ + Footer *footer() const; + + /*! + * Returns a reference to the item list map. This is an ItemListMap of + * all of the items in the tag. + * + * This is the most powerfull structure for accessing the items of the tag. + * + * \warning You should not modify this data structure directly, instead + * use setItem() and removeItem(). + */ + const ItemListMap &itemListMap() const; + + /*! + * Removes the \a key item from the tag + */ + void removeItem(const String &key); + + /*! + * Adds to the item specified by \a key the data \a value. If \a replace + * is true, then all of the other values on the same key will be removed + * first. + */ + void addValue(const String &key, const String &value, bool replace = true); + + /*! + * Sets the \a key item to the value of \a item. If an item with the \a key is already + * present, it will be replaced. + */ + void setItem(const String &key, const Item &item); + + protected: + + /*! + * Reads from the file specified in the constructor. + */ + void read(); + + /*! + * Parses the body of the tag in \a data. + */ + void parse(const ByteVector &data); + + private: + Tag(const Tag &); + Tag &operator=(const Tag &); + + class TagPrivate; + TagPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/audioproperties.cpp b/Libraries/TagLib/Files/taglib/audioproperties.cpp new file mode 100644 index 000000000..48e620fe0 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/audioproperties.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "audioproperties.h" + +using namespace TagLib; + +class AudioProperties::AudioPropertiesPrivate +{ + +}; + +//////////////////////////////////////////////////////////////////////////////// +// public methods +//////////////////////////////////////////////////////////////////////////////// + +AudioProperties::~AudioProperties() +{ + +} + +//////////////////////////////////////////////////////////////////////////////// +// protected methods +//////////////////////////////////////////////////////////////////////////////// + +AudioProperties::AudioProperties(ReadStyle) +{ + +} diff --git a/Libraries/TagLib/Files/taglib/audioproperties.h b/Libraries/TagLib/Files/taglib/audioproperties.h new file mode 100644 index 000000000..4584b8693 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/audioproperties.h @@ -0,0 +1,104 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_AUDIOPROPERTIES_H +#define TAGLIB_AUDIOPROPERTIES_H + +namespace TagLib { + + //! A simple, abstract interface to common audio properties + + /*! + * The values here are common to most audio formats. For more specific, codec + * dependant values, please see see the subclasses APIs. This is meant to + * compliment the TagLib::File and TagLib::Tag APIs in providing a simple + * interface that is sufficient for most applications. + */ + + class AudioProperties + { + public: + + /*! + * Reading audio properties from a file can sometimes be very time consuming + * and for the most accurate results can often involve reading the entire + * file. Because in many situations speed is critical or the accuracy of the + * values is not particularly important this allows the level of desired + * accuracy to be set. + */ + enum ReadStyle { + //! Read as little of the file as possible + Fast, + //! Read more of the file and make better values guesses + Average, + //! Read as much of the file as needed to report accurate values + Accurate + }; + + /*! + * Destroys this AudioProperties instance. + */ + virtual ~AudioProperties(); + + /*! + * Returns the lenght of the file in seconds. + */ + virtual int length() const = 0; + + /*! + * Returns the most appropriate bit rate for the file in kb/s. For constant + * bitrate formats this is simply the bitrate of the file. For variable + * bitrate formats this is either the average or nominal bitrate. + */ + virtual int bitrate() const = 0; + + /*! + * Returns the sample rate in Hz. + */ + virtual int sampleRate() const = 0; + + /*! + * Returns the number of audio channels. + */ + virtual int channels() const = 0; + + protected: + + /*! + * Construct an audio properties instance. This is protected as this class + * should not be instantiated directly, but should be instantiated via its + * subclasses and can be fetched from the FileRef or File APIs. + * + * \see ReadStyle + */ + AudioProperties(ReadStyle style); + + private: + AudioProperties(const AudioProperties &); + AudioProperties &operator=(const AudioProperties &); + + class AudioPropertiesPrivate; + AudioPropertiesPrivate *d; + }; + +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/configure.in.bot b/Libraries/TagLib/Files/taglib/configure.in.bot new file mode 100644 index 000000000..b3e513c0d --- /dev/null +++ b/Libraries/TagLib/Files/taglib/configure.in.bot @@ -0,0 +1,8 @@ +if test "x$have_zlib" = "xfalse"; then + echo "**************************************************" + echo "*" + echo "* You don't seem to have libz / zlib.h installed." + echo "* Compressed frames have been disabled." + echo "*" + echo "**************************************************" +fi diff --git a/Libraries/TagLib/Files/taglib/configure.in.in b/Libraries/TagLib/Files/taglib/configure.in.in new file mode 100644 index 000000000..9d678d6df --- /dev/null +++ b/Libraries/TagLib/Files/taglib/configure.in.in @@ -0,0 +1,18 @@ +#AM_INIT_AUTOMAKE(taglib,1.0) +dnl don't remove the below +dnl AC_OUTPUT(taglib/taglib-config) + +AC_DEFUN([AC_HAVE_ZLIB], +[ + AC_DEFINE(HAVE_ZLIB, 1, [have zlib]) + have_zlib=true +]) + +AC_DEFUN([AC_NO_ZLIB], +[ + AC_DEFINE(HAVE_ZLIB, 0, [have zlib]) + have_zlib=false +]) + +AC_CHECK_HEADER(zlib.h, AC_HAVE_ZLIB, AC_NO_ZLIB) +AM_CONDITIONAL(link_zlib, test x$have_zlib = xtrue) diff --git a/Libraries/TagLib/Files/taglib/fileref.cpp b/Libraries/TagLib/Files/taglib/fileref.cpp new file mode 100644 index 000000000..2da2e71ff --- /dev/null +++ b/Libraries/TagLib/Files/taglib/fileref.cpp @@ -0,0 +1,143 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "fileref.h" +#include "mpegfile.h" +#include "vorbisfile.h" +#include "flacfile.h" +#include "mpcfile.h" + +using namespace TagLib; + +class FileRef::FileRefPrivate : public RefCounter +{ +public: + FileRefPrivate(File *f) : RefCounter(), file(f) {} + ~FileRefPrivate() { + delete file; + } + + File *file; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +FileRef::FileRef() +{ + d = new FileRefPrivate(0); +} + +FileRef::FileRef(const char *fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) +{ + d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle)); +} + +FileRef::FileRef(File *file) +{ + d = new FileRefPrivate(file); +} + +FileRef::FileRef(const FileRef &ref) : d(ref.d) +{ + d->ref(); +} + +FileRef::~FileRef() +{ + if(d->deref()) + delete d; +} + +Tag *FileRef::tag() const +{ + return d->file->tag(); +} + +AudioProperties *FileRef::audioProperties() const +{ + return d->file->audioProperties(); +} + +File *FileRef::file() const +{ + return d->file; +} + +bool FileRef::save() +{ + return d->file->save(); +} + +bool FileRef::isNull() const +{ + return !d->file || !d->file->isValid(); +} + +FileRef &FileRef::operator=(const FileRef &ref) +{ + if(&ref == this) + return *this; + + if(d->deref()) + delete d; + + d = ref.d; + d->ref(); + + return *this; +} + +bool FileRef::operator==(const FileRef &ref) const +{ + return ref.d->file == d->file; +} + +bool FileRef::operator!=(const FileRef &ref) const +{ + return ref.d->file != d->file; +} + +File *FileRef::create(const char *fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) // static +{ + // Ok, this is really dumb for now, but it works for testing. + + String s = fileName; + + if(s.size() > 4) { + if(s.substr(s.size() - 4, 4).upper() == ".OGG") + return new Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); + if(s.substr(s.size() - 4, 4).upper() == ".MP3") + return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); + if(s.substr(s.size() - 5, 5).upper() == ".FLAC") + return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); + if(s.substr(s.size() - 4, 4).upper() == ".MPC") + return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle); + } + + return 0; +} diff --git a/Libraries/TagLib/Files/taglib/fileref.h b/Libraries/TagLib/Files/taglib/fileref.h new file mode 100644 index 000000000..ffa7864fc --- /dev/null +++ b/Libraries/TagLib/Files/taglib/fileref.h @@ -0,0 +1,183 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_FILEREF_H +#define TAGLIB_FILEREF_H + +#include "audioproperties.h" + +namespace TagLib { + + class String; + class File; + class Tag; + + //! This class provides a simple abstraction for creating and handling files + + /*! + * FileRef exists to provide a minimal, generic and value-based wrapper around + * a File. It is lightweight and implicitly shared, and as such suitable for + * pass-by-value use. This hides some of the uglier details of TagLib::File + * and the non-generic portions of the concrete file implementations. + * + * This class is useful in a "simple usage" situation where it is desirable + * to be able to get and set some of the tag information that is similar + * across file types. + * + * Also note that it is probably a good idea to plug this into your mime + * type system rather than using the constructor that accepts a file name. + * + * For example in KDE this could be done with: + * + * \code + * + * TagLib::FileRef createFileRef( const QString &fileName ) + * { + * KMimeType::Ptr result = KMimeType::findByPath( fileName, 0, true ); + * + * if( result->name() == "audio/x-mp3" ) + * return FileRef( new MPEG::File( QFile::encodeName( fileName ).data() ) ); + * + * if( result->name() == "application/ogg" ) + * return FileRef( new Vorbis::File( QFile::encodeName( fileName ).data() ) ); + * + * return FileRef( 0 ); + * } + * + * \endcode + */ + + class FileRef + { + public: + + FileRef(); + + /*! + * Create a FileRef from \a fileName. If \a readAudioProperties is true then + * the audio properties will be read using \a audioPropertiesStyle. If + * \a readAudioProperties is false then \a audioPropertiesStyle will be + * ignored. + * + * Also see the note in the class documentation about why you may not want to + * use this method in your application. + */ + explicit FileRef(const char *fileName, + bool readAudioProperties = true, + AudioProperties::ReadStyle + audioPropertiesStyle = AudioProperties::Average); + + /*! + * Contruct a FileRef using \a file. The FileRef now takes ownership of the + * pointer and will delete the File when it passes out of scope. + */ + explicit FileRef(File *file); + + /*! + * Make a copy of \a ref. + */ + FileRef(const FileRef &ref); + + /*! + * Destroys this FileRef instance. + */ + virtual ~FileRef(); + + /*! + * Returns a pointer to represented file's tag. + * + * \warning This pointer will become invalid when this FileRef and all + * copies pass out of scope. + * + * \see File::tag() + */ + Tag *tag() const; + + /*! + * Returns the audio properties for this FileRef. If no audio properties + * were read then this will returns a null pointer. + */ + AudioProperties *audioProperties() const; + + /*! + * Returns a pointer to the file represented by this handler class. + * + * As a general rule this call should be avoided since if you need to work + * with file objects directly, you are probably better served instantiating + * the File subclasses (i.e. MPEG::File) manually and working with their APIs. + * + * This handle exists to provide a minimal, generic and value-based + * wrapper around a File. Accessing the file directly generally indicates + * a moving away from this simplicity (and into things beyond the scope of + * FileRef). + * + * \warning This pointer will become invalid when this FileRef and all + * copies pass out of scope. + */ + File *file() const; + + /*! + * Saves the file. Returns true on success. + */ + bool save(); + + /*! + * Returns true if the file (and as such other pointers) are null. + */ + bool isNull() const; + + /*! + * Assign the file pointed to by \a ref to this FileRef. + */ + FileRef &operator=(const FileRef &ref); + + /*! + * Returns true if this FileRef and \a ref point to the same File object. + */ + bool operator==(const FileRef &ref) const; + + /*! + * Returns true if this FileRef and \a ref do not point to the same File + * object. + */ + bool operator!=(const FileRef &ref) const; + + /*! + * A simple implementation of file type guessing. If \a readAudioProperties + * is true then the audio properties will be read using + * \a audioPropertiesStyle. If \a readAudioProperties is false then + * \a audioPropertiesStyle will be ignored. + * + * \note You generally shouldn't use this method, but instead the constructor + * directly. + */ + static File *create(const char *fileName, + bool readAudioProperties = true, + AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); + + private: + class FileRefPrivate; + FileRefPrivate *d; + }; + +} // namespace TagLib + +#endif diff --git a/Libraries/TagLib/Files/taglib/flac/Makefile.am b/Libraries/TagLib/Files/taglib/flac/Makefile.am new file mode 100644 index 000000000..40caf2ea9 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/flac/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ogg \ + -I$(top_srcdir)/taglib/mpeg/id3v2 \ + -I$(top_srcdir)/taglib/mpeg/id3v1 \ + $(all_includes) + +noinst_LTLIBRARIES = libflac.la + +libflac_la_SOURCES = flacfile.cpp flacproperties.cpp + +taglib_include_HEADERS = flacfile.h flacproperties.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libflac_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/flac/Makefile.in b/Libraries/TagLib/Files/taglib/flac/Makefile.in new file mode 100644 index 000000000..6a56a311f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/flac/Makefile.in @@ -0,0 +1,555 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ogg \ + -I$(top_srcdir)/taglib/mpeg/id3v2 \ + -I$(top_srcdir)/taglib/mpeg/id3v1 \ + $(all_includes) + + +noinst_LTLIBRARIES = libflac.la + +libflac_la_SOURCES = flacfile.cpp flacproperties.cpp + +taglib_include_HEADERS = flacfile.h flacproperties.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libflac_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/flac +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libflac_la_LDFLAGS = +libflac_la_LIBADD = +am_libflac_la_OBJECTS = flacfile.lo flacproperties.lo +#>- libflac_la_OBJECTS = $(am_libflac_la_OBJECTS) +#>+ 4 +libflac_la_final_OBJECTS = libflac_la.all_cpp.lo +libflac_la_nofinal_OBJECTS = flacfile.lo flacproperties.lo +@KDE_USE_FINAL_FALSE@libflac_la_OBJECTS = $(libflac_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libflac_la_OBJECTS = $(libflac_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/flacfile.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/flacproperties.Plo +#>+ 5 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libflac_la.all_cpp.P ./$(DEPDIR)/flacfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/flacproperties.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/flacfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/flacproperties.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libflac_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(libflac_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/flac/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/flac/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/flac/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libflac.la: $(libflac_la_OBJECTS) $(libflac_la_DEPENDENCIES) + $(CXXLINK) $(libflac_la_LDFLAGS) $(libflac_la_OBJECTS) $(libflac_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flacfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flacproperties.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +#>- DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +#>+ 4 +KDE_DIST=flactag.h + +DISTFILES= $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) $(KDE_DIST) + + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/flac/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/flac/Makefile.in + + +#>+ 11 +libflac_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/flacfile.cpp $(srcdir)/flacproperties.cpp + @echo 'creating libflac_la.all_cpp.cpp ...'; \ + rm -f libflac_la.all_cpp.files libflac_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libflac_la.all_cpp.final; \ + for file in flacfile.cpp flacproperties.cpp ; do \ + echo "#include \"$$file\"" >> libflac_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libflac_la.all_cpp.final; \ + done; \ + cat libflac_la.all_cpp.final libflac_la.all_cpp.files > libflac_la.all_cpp.cpp; \ + rm -f libflac_la.all_cpp.final libflac_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libflac_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libflac_la_OBJECTS="$(libflac_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libflac_la_OBJECTS="$(libflac_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libflac_la_OBJECTS="$(libflac_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libflac_la_OBJECTS="$(libflac_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/flac/flacfile.cpp b/Libraries/TagLib/Files/taglib/flac/flacfile.cpp new file mode 100644 index 000000000..a60e02e20 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/flac/flacfile.cpp @@ -0,0 +1,468 @@ +/*************************************************************************** + copyright : (C) 2003-2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "flacfile.h" +#include "flactag.h" + +using namespace TagLib; + +namespace TagLib { +namespace FLAC { + enum BLOCK_TYPE { STREAMINFO = 0, PADDING, APPLICATION, SEEKTABLE, VORBISCOMMENT, CUESHEET }; +}} + +class FLAC::File::FilePrivate +{ +public: + FilePrivate() : + ID3v2FrameFactory(ID3v2::FrameFactory::instance()), + ID3v2Tag(0), + ID3v2Location(-1), + ID3v2OriginalSize(0), + ID3v1Tag(0), + ID3v1Location(-1), + comment(0), + properties(0), + flacStart(0), + streamStart(0), + streamLength(0), + scanned(false), + hasXiphComment(false), + hasID3v2(false), + hasID3v1(false) {} + + ~FilePrivate() + { + delete ID3v2Tag; + delete ID3v1Tag; + delete comment; + delete properties; + } + + const ID3v2::FrameFactory *ID3v2FrameFactory; + ID3v2::Tag *ID3v2Tag; + long ID3v2Location; + uint ID3v2OriginalSize; + + ID3v1::Tag *ID3v1Tag; + long ID3v1Location; + + Ogg::XiphComment *comment; + + FLAC::Tag *tag; + + Properties *properties; +// Map metaData; + ByteVector streamInfoData; + ByteVector xiphCommentData; + long flacStart; + long streamStart; + long streamLength; + bool scanned; + + bool hasXiphComment; + bool hasID3v2; + bool hasID3v1; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +FLAC::File::File(const char *file, bool readProperties, + Properties::ReadStyle propertiesStyle) : + TagLib::File(file) +{ + d = new FilePrivate; + read(readProperties, propertiesStyle); +} + +FLAC::File::File(const char *file, ID3v2::FrameFactory *frameFactory, + bool readProperties, Properties::ReadStyle propertiesStyle) : + TagLib::File(file) +{ + d = new FilePrivate; + d->ID3v2FrameFactory = frameFactory; + read(readProperties, propertiesStyle); +} + +FLAC::File::~File() +{ + delete d; +} + +TagLib::Tag *FLAC::File::tag() const +{ + return d->tag; +} + +FLAC::Properties *FLAC::File::audioProperties() const +{ + return d->properties; +} + + +bool FLAC::File::save() +{ + if(readOnly()) { + debug("FLAC::File::save() - Cannot save to a read only file."); + return false; + } + + // Create new vorbis comments + + if(!d->comment) { + d->comment = new Ogg::XiphComment; + if(d->tag) + Tag::duplicate(d->tag, d->comment, true); + } + + d->xiphCommentData = d->comment->render(false); + + ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size()); + + // Set the type of the comment to be a Xiph / Vorbis comment + // (See scan() for comments on header-format) + v[0] = 4; + v.append(d->xiphCommentData); + + + // If file already have comment => find and update it + // if not => insert one + // TODO: Search for padding and use that + + if(d->hasXiphComment) { + long nextPageOffset = d->flacStart; + seek(nextPageOffset); + ByteVector header = readBlock(4); + uint length = header.mid(1, 3).toUInt(); + + nextPageOffset += length + 4; + + // Search through the remaining metadata + + char blockType = header[0] & 0x7f; + bool lastBlock = header[0] & 0x80; + + while(!lastBlock) { + seek(nextPageOffset); + + header = readBlock(4); + blockType = header[0] & 0x7f; + lastBlock = header[0] & 0x80; + length = header.mid(1, 3).toUInt(); + + // Type is vorbiscomment + if(blockType == 4) { + v[0] = header[0]; + insert(v, nextPageOffset, length + 4); + break; + } + + nextPageOffset += length + 4; + } + } + else { + long nextPageOffset = d->flacStart; + + seek(nextPageOffset); + + ByteVector header = readBlock(4); + // char blockType = header[0] & 0x7f; + bool lastBlock = header[0] & 0x80; + uint length = header.mid(1, 3).toUInt(); + + // If last block was last, make this one last + + if(lastBlock) { + + // Copy the bottom seven bits into the new value + + ByteVector h(static_cast(header[0] & 0x7F)); + insert(h, nextPageOffset, 1); + + // Set the last bit + v[0] |= 0x80; + } + + insert(v, nextPageOffset + length + 4, 0); + d->hasXiphComment = true; + } + + // Update ID3 tags + + if(d->ID3v2Tag) { + if(d->hasID3v2) + insert(d->ID3v2Tag->render(), d->ID3v2Location, d->ID3v2OriginalSize); + else + insert(d->ID3v2Tag->render(), 0, 0); + } + + if(d->ID3v1Tag) { + if(d->hasID3v1) + seek(-128, End); + else + seek(0, End); + writeBlock(d->ID3v1Tag->render()); + } + + return true; +} + +ID3v2::Tag *FLAC::File::ID3v2Tag(bool create) +{ + if(!create || d->ID3v2Tag) + return d->ID3v2Tag; + + // no ID3v2 tag exists and we've been asked to create one + + d->ID3v2Tag = new ID3v2::Tag; + return d->ID3v2Tag; +} + +ID3v1::Tag *FLAC::File::ID3v1Tag(bool create) +{ + if(!create || d->ID3v1Tag) + return d->ID3v1Tag; + + // no ID3v1 tag exists and we've been asked to create one + + d->ID3v1Tag = new ID3v1::Tag; + return d->ID3v1Tag; +} + +Ogg::XiphComment *FLAC::File::xiphComment(bool create) +{ + if(!create || d->comment) + return d->comment; + + // no XiphComment exists and we've been asked to create one + + d->comment = new Ogg::XiphComment; + return d->comment; +} + +void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) +{ + d->ID3v2FrameFactory = factory; +} + + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) +{ + // Look for an ID3v2 tag + + d->ID3v2Location = findID3v2(); + + if(d->ID3v2Location >= 0) { + + d->ID3v2Tag = new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory); + + d->ID3v2OriginalSize = d->ID3v2Tag->header()->completeTagSize(); + + if(d->ID3v2Tag->header()->tagSize() <= 0) { + delete d->ID3v2Tag; + d->ID3v2Tag = 0; + } + else + d->hasID3v2 = true; + } + + // Look for an ID3v1 tag + + d->ID3v1Location = findID3v1(); + + if(d->ID3v1Location >= 0) { + d->ID3v1Tag = new ID3v1::Tag(this, d->ID3v1Location); + d->hasID3v1 = true; + } + + // Look for FLAC metadata, including vorbis comments + + scan(); + + if (!isValid()) return; + + if(d->hasXiphComment) + d->comment = new Ogg::XiphComment(xiphCommentData()); + + if(d->hasXiphComment || d->hasID3v2 || d->hasID3v1) + d->tag = new FLAC::Tag(d->comment, d->ID3v2Tag, d->ID3v1Tag); + else + d->tag = new FLAC::Tag(new Ogg::XiphComment); + + if(readProperties) + d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle); +} + +ByteVector FLAC::File::streamInfoData() +{ + if (isValid()) + return d->streamInfoData; +// return d->metaData[STREAMINFO]; + else + return ByteVector(); +} + +ByteVector FLAC::File::xiphCommentData() +{ + if (isValid() && d->hasXiphComment) + return d->xiphCommentData; +// return d->metaData[VORBISCOMMENT]; + else + return ByteVector(); +} + +long FLAC::File::streamLength() +{ + return d->streamLength; +} + +void FLAC::File::scan() +{ + // Scan the metadata pages + + if(d->scanned) + return; + + if(!isValid()) + return; + + long nextPageOffset; + long fileSize = length(); + + if (d->hasID3v2) + nextPageOffset = find("fLaC", d->ID3v2Location+d->ID3v2OriginalSize); + else + nextPageOffset = find("fLaC"); + + if(nextPageOffset < 0) { + debug("FLAC::File::scan() -- FLAC stream not found"); + setValid(false); + return; + } + + nextPageOffset += 4; + d->flacStart = nextPageOffset; + + seek(nextPageOffset); + + ByteVector header = readBlock(4); + + // Header format (from spec): + // <1> Last-metadata-block flag + // <7> BLOCK_TYPE + // 0 : STREAMINFO + // 1 : PADDING + // .. + // 4 : VORBIS_COMMENT + // .. + // <24> Length of metadata to follow + + char blockType = header[0] & 0x7f; + bool lastBlock = header[0] & 0x80; + uint length = header.mid(1, 3).toUInt(); + + // First block should be the stream_info metadata + if(blockType != 0) { + debug("FLAC::File::scan() -- invalid FLAC stream"); + setValid(false); + return; + } + d->streamInfoData = readBlock(length); +// d->metadata.insert(STREAMINFO, readBlock(length)); + nextPageOffset += length + 4; + + // Search through the remaining metadata + + while(!lastBlock) { + header = readBlock(4); + blockType = header[0] & 0x7f; + lastBlock = header[0] & 0x80; + length = header.mid(1, 3).toUInt(); + + if(blockType == 1) { + // debug("FLAC::File::scan() -- Padding found"); + } + // Found the vorbis-comment + else if(blockType == 4) { + d->xiphCommentData = readBlock(length); +// d->metadata.insert(VORBISCOMMENT, readBlock(length)); + d->hasXiphComment = true; + } + + nextPageOffset += length + 4; + if (nextPageOffset >= fileSize) { + debug("FLAC::File::scan() -- FLAC stream corrupted"); + setValid(false); + return; + } + seek(nextPageOffset); + } + + // End of metadata, now comes the datastream + d->streamStart = nextPageOffset; + d->streamLength = File::length() - d->streamStart; + if (d->hasID3v1) + d->streamLength -= 128; + + d->scanned = true; +} + +long FLAC::File::findID3v1() +{ + if(!isValid()) + return -1; + + seek(-128, End); + long p = tell(); + + if(readBlock(3) == ID3v1::Tag::fileIdentifier()) + return p; + + return -1; +} + +long FLAC::File::findID3v2() +{ + if(!isValid()) + return -1; + + seek(0); + + if(readBlock(3) == ID3v2::Header::fileIdentifier()) + return 0; + + return -1; +} diff --git a/Libraries/TagLib/Files/taglib/flac/flacfile.h b/Libraries/TagLib/Files/taglib/flac/flacfile.h new file mode 100644 index 000000000..9fef90398 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/flac/flacfile.h @@ -0,0 +1,196 @@ +/*************************************************************************** + copyright : (C) 2003 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_FLACFILE_H +#define TAGLIB_FLACFILE_H + +#include + +#include "flacproperties.h" + +namespace TagLib { + + class Tag; + + namespace ID3v2 { class FrameFactory; class Tag; } + namespace ID3v1 { class Tag; } + namespace Ogg { class XiphComment; } + + //! An implementation of FLAC metadata + + /*! + * This is implementation of FLAC metadata for non-Ogg FLAC files. At some + * point when Ogg / FLAC is more common there will be a similar implementation + * under the Ogg hiearchy. + * + * This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream + * properties from the file. + */ + + namespace FLAC { + + //! An implementation of TagLib::File with FLAC specific methods + + /*! + * This implements and provides an interface for FLAC files to the + * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing + * the abstract TagLib::File API as well as providing some additional + * information specific to FLAC files. + */ + + class File : public TagLib::File + { + public: + /*! + * Contructs a FLAC file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + * + * \deprecated This constructor will be dropped in favor of the one below + * in a future version. + */ + File(const char *file, bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Contructs a FLAC file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + * + * If this file contains and ID3v2 tag the frames will be created using + * \a frameFactory. + */ + // BIC: merge with the above constructor + File(const char *file, ID3v2::FrameFactory *frameFactory, + bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns the Tag for this file. This will be a union of XiphComment, + * ID3v1 and ID3v2 tags. + * + * \see ID3v2Tag() + * \see ID3v1Tag() + * \see XiphComment() + */ + virtual TagLib::Tag *tag() const; + + /*! + * Returns the FLAC::Properties for this file. If no audio properties + * were read then this will return a null pointer. + */ + virtual Properties *audioProperties() const; + + /*! + * Save the file. This will primarily save the XiphComment, but + * will also keep any old ID3-tags up to date. If the file + * has no XiphComment, one will be constructed from the ID3-tags. + * + * This returns true if the save was successful. + */ + virtual bool save(); + + /*! + * Returns a pointer to the ID3v2 tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid ID3v2 tag. If \a create is true it will create + * an ID3v2 tag if one does not exist. + * + * \note The Tag is still owned by the FLAC::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + ID3v2::Tag *ID3v2Tag(bool create = false); + + /*! + * Returns a pointer to the ID3v1 tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid ID3v1 tag. If \a create is true it will create + * an ID3v1 tag if one does not exist. + * + * \note The Tag is still owned by the FLAC::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + ID3v1::Tag *ID3v1Tag(bool create = false); + + /*! + * Returns a pointer to the XiphComment for the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid XiphComment. If \a create is true it will create + * a XiphComment if one does not exist. + * + * \note The Tag is still owned by the FLAC::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + Ogg::XiphComment *xiphComment(bool create = false); + + /*! + * Set the ID3v2::FrameFactory to something other than the default. This + * can be used to specify the way that ID3v2 frames will be interpreted + * when + * + * \see ID3v2FrameFactory + */ + void setID3v2FrameFactory(const ID3v2::FrameFactory *factory); + + /*! + * Returns the block of data used by FLAC::Properties for parsing the + * stream properties. + * + * \deprecated This method will not be public in a future release. + */ + ByteVector streamInfoData(); // BIC: remove + + /*! + * Returns the length of the audio-stream, used by FLAC::Properties for + * calculating the bitrate. + * + * \deprecated This method will not be public in a future release. + */ + long streamLength(); // BIC: remove + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + void scan(); + long findID3v2(); + long findID3v1(); + ByteVector xiphCommentData(); + + class FilePrivate; + FilePrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/flac/flacproperties.cpp b/Libraries/TagLib/Files/taglib/flac/flacproperties.cpp new file mode 100644 index 000000000..821de3ca4 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/flac/flacproperties.cpp @@ -0,0 +1,146 @@ +/*************************************************************************** + copyright : (C) 2003 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "flacproperties.h" +#include "flacfile.h" + +using namespace TagLib; + +class FLAC::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate(ByteVector d, long st, ReadStyle s) : + data(d), + streamLength(st), + style(s), + length(0), + bitrate(0), + sampleRate(0), + sampleWidth(0), + channels(0) {} + + ByteVector data; + long streamLength; + ReadStyle style; + int length; + int bitrate; + int sampleRate; + int sampleWidth; + int channels; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style) +{ + d = new PropertiesPrivate(data, streamLength, style); + read(); +} + +FLAC::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) +{ + d = new PropertiesPrivate(file->streamInfoData(), file->streamLength(), style); + read(); +} + +FLAC::Properties::~Properties() +{ + delete d; +} + +int FLAC::Properties::length() const +{ + return d->length; +} + +int FLAC::Properties::bitrate() const +{ + return d->bitrate; +} + +int FLAC::Properties::sampleRate() const +{ + return d->sampleRate; +} + +int FLAC::Properties::sampleWidth() const +{ + return d->sampleWidth; +} + +int FLAC::Properties::channels() const +{ + return d->channels; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void FLAC::Properties::read() +{ + if(d->data.size() < 18) { + debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes."); + return; + } + + int pos = 0; + + // Minimum block size (in samples) + pos += 2; + + // Maximum block size (in samples) + pos += 2; + + // Minimum frame size (in bytes) + pos += 3; + + // Maximum frame size (in bytes) + pos += 3; + + uint flags = d->data.mid(pos, 4).toUInt(true); + d->sampleRate = flags >> 12; + d->channels = ((flags >> 9) & 7) + 1; + d->sampleWidth = ((flags >> 4) & 31) + 1; + + // The last 4 bits are the most significant 4 bits for the 36 bit + // stream length in samples. (Audio files measured in days) + + uint highLength =d->sampleRate > 0 ? (((flags & 0xf) << 28) / d->sampleRate) << 4 : 0; + pos += 4; + + d->length = d->sampleRate > 0 ? + (d->data.mid(pos, 4).toUInt(true)) / d->sampleRate + highLength : 0; + pos += 4; + + // Uncompressed bitrate: + + //d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth; + + // Real bitrate: + + d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; +} diff --git a/Libraries/TagLib/Files/taglib/flac/flacproperties.h b/Libraries/TagLib/Files/taglib/flac/flacproperties.h new file mode 100644 index 000000000..c1d1a4fae --- /dev/null +++ b/Libraries/TagLib/Files/taglib/flac/flacproperties.h @@ -0,0 +1,84 @@ +/*************************************************************************** + copyright : (C) 2003 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_FLACPROPERTIES_H +#define TAGLIB_FLACPROPERTIES_H + +#include + +namespace TagLib { + + namespace FLAC { + + class File; + + //! An implementation of audio property reading for FLAC + + /*! + * This reads the data from an FLAC stream found in the AudioProperties + * API. + */ + + class Properties : public AudioProperties + { + public: + /*! + * Create an instance of FLAC::Properties with the data read from the + * ByteVector \a data. + */ + // BIC: switch to const reference + Properties(ByteVector data, long streamLength, ReadStyle style = Average); + + /*! + * Create an instance of FLAC::Properties with the data read from the + * FLAC::File \a file. + */ + // BIC: remove + Properties(File *file, ReadStyle style = Average); + + /*! + * Destroys this FLAC::Properties instance. + */ + virtual ~Properties(); + + // Reimplementations. + + virtual int length() const; + virtual int bitrate() const; + virtual int sampleRate() const; + virtual int channels() const; + + /*! + * Returns the sample width as read from the FLAC identification + * header. + */ + int sampleWidth() const; + + private: + void read(); + + class PropertiesPrivate; + PropertiesPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/flac/flactag.h b/Libraries/TagLib/Files/taglib/flac/flactag.h new file mode 100644 index 000000000..89d4b63e6 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/flac/flactag.h @@ -0,0 +1,212 @@ +/*************************************************************************** + copyright : (C) 2003 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef DO_NOT_DOCUMENT // Tell Doxygen not to document this header + +#ifndef TAGLIB_FLACTAG_H +#define TAGLIB_FLACTAG_H + +//////////////////////////////////////////////////////////////////////////////// +// Note that this header is not installed. +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +namespace TagLib { + + namespace FLAC { + + /*! + * A union of Xiph, ID3v2 and ID3v1 tags. + */ + class Tag : public TagLib::Tag + { + public: + Tag(Ogg::XiphComment *xiph, ID3v2::Tag *id3v2 = 0, ID3v1::Tag *id3v1 = 0) : + TagLib::Tag(), + xiph(xiph), id3v2(id3v2), id3v1(id3v1) {} + + virtual String title() const { + if(xiph && !xiph->title().isEmpty()) + return xiph->title(); + + if(id3v2 && !id3v2->title().isEmpty()) + return id3v2->title(); + + if(id3v1) + return id3v1->title(); + + return String::null; + } + + virtual String artist() const { + if(xiph && !xiph->artist().isEmpty()) + return xiph->artist(); + + if(id3v2 && !id3v2->artist().isEmpty()) + return id3v2->artist(); + + if(id3v1) + return id3v1->artist(); + + return String::null; + } + + virtual String album() const { + if(xiph && !xiph->album().isEmpty()) + return xiph->album(); + + if(id3v2 && !id3v2->album().isEmpty()) + return id3v2->album(); + + if(id3v1) + return id3v1->album(); + + return String::null; + } + + virtual String comment() const { + if(xiph && !xiph->comment().isEmpty()) + return xiph->comment(); + + if(id3v2 && !id3v2->comment().isEmpty()) + return id3v2->comment(); + + if(id3v1) + return id3v1->comment(); + + return String::null; + } + + virtual String genre() const { + if(xiph && !xiph->genre().isEmpty()) + return xiph->genre(); + + if(id3v2 && !id3v2->genre().isEmpty()) + return id3v2->genre(); + + if(id3v1) + return id3v1->genre(); + + return String::null; + } + + virtual uint year() const { + if(xiph && xiph->year() > 0) + return xiph->year(); + + if(id3v2 && id3v2->year() > 0) + return id3v2->year(); + + if(id3v1) + return id3v1->year(); + + return 0; + } + + virtual uint track() const { + if(xiph && xiph->track() > 0) + return xiph->track(); + + if(id3v2 && id3v2->track() > 0) + return id3v2->track(); + + if(id3v1) + return id3v1->track(); + + return 0; + } + + virtual void setTitle(const String &s) { + if(xiph) + xiph->setTitle(s); + if(id3v2) + id3v2->setTitle(s); + if(id3v1) + id3v1->setTitle(s); + } + + virtual void setArtist(const String &s) { + if(xiph) + xiph->setArtist(s); + if(id3v2) + id3v2->setArtist(s); + if(id3v1) + id3v1->setArtist(s); + } + + virtual void setAlbum(const String &s) { + if(xiph) + xiph->setAlbum(s); + if(id3v2) + id3v2->setAlbum(s); + if(id3v1) + id3v1->setAlbum(s); + } + + virtual void setComment(const String &s) { + if(xiph) + xiph->setComment(s); + if(id3v2) + id3v2->setComment(s); + if(id3v1) + id3v1->setComment(s); + } + + virtual void setGenre(const String &s) { + if(xiph) + xiph->setGenre(s); + if(id3v2) + id3v2->setGenre(s); + if(id3v1) + id3v1->setGenre(s); + } + + virtual void setYear(uint i) { + if(xiph) + xiph->setYear(i); + if(id3v2) + id3v2->setYear(i); + if(id3v1) + id3v1->setYear(i); + } + + virtual void setTrack(uint i) { + if(xiph) + xiph->setTrack(i); + if(id3v2) + id3v2->setTrack(i); + if(id3v1) + id3v1->setTrack(i); + } + + private: + Ogg::XiphComment *xiph; + ID3v2::Tag *id3v2; + ID3v1::Tag *id3v1; + }; + } +} + +#endif +#endif diff --git a/Libraries/TagLib/Files/taglib/mpc/Makefile.am b/Libraries/TagLib/Files/taglib/mpc/Makefile.am new file mode 100644 index 000000000..4d12cb660 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpc/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ape \ + -I$(top_srcdir)/taglib/mpeg/id3v1 \ + -I$(top_srcdir)/taglib/mpeg/id3v2 \ + $(all_includes) + +noinst_LTLIBRARIES = libmpc.la + +libmpc_la_SOURCES = mpcfile.cpp mpcproperties.cpp + +taglib_include_HEADERS = mpcfile.h mpcproperties.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libmpc_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/mpc/Makefile.in b/Libraries/TagLib/Files/taglib/mpc/Makefile.in new file mode 100644 index 000000000..c62a8e7ba --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpc/Makefile.in @@ -0,0 +1,555 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ape \ + -I$(top_srcdir)/taglib/mpeg/id3v1 \ + -I$(top_srcdir)/taglib/mpeg/id3v2 \ + $(all_includes) + + +noinst_LTLIBRARIES = libmpc.la + +libmpc_la_SOURCES = mpcfile.cpp mpcproperties.cpp + +taglib_include_HEADERS = mpcfile.h mpcproperties.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libmpc_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/mpc +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libmpc_la_LDFLAGS = +libmpc_la_LIBADD = +am_libmpc_la_OBJECTS = mpcfile.lo mpcproperties.lo +#>- libmpc_la_OBJECTS = $(am_libmpc_la_OBJECTS) +#>+ 4 +libmpc_la_final_OBJECTS = libmpc_la.all_cpp.lo +libmpc_la_nofinal_OBJECTS = mpcfile.lo mpcproperties.lo +@KDE_USE_FINAL_FALSE@libmpc_la_OBJECTS = $(libmpc_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libmpc_la_OBJECTS = $(libmpc_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/mpcfile.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/mpcproperties.Plo +#>+ 5 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libmpc_la.all_cpp.P ./$(DEPDIR)/mpcfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/mpcproperties.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/mpcfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/mpcproperties.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libmpc_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(libmpc_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/mpc/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpc/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpc/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmpc.la: $(libmpc_la_OBJECTS) $(libmpc_la_DEPENDENCIES) + $(CXXLINK) $(libmpc_la_LDFLAGS) $(libmpc_la_OBJECTS) $(libmpc_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpcfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpcproperties.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +#>- DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +#>+ 4 +KDE_DIST=combinedtag.h + +DISTFILES= $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) $(KDE_DIST) + + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpc/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpc/Makefile.in + + +#>+ 11 +libmpc_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/mpcfile.cpp $(srcdir)/mpcproperties.cpp + @echo 'creating libmpc_la.all_cpp.cpp ...'; \ + rm -f libmpc_la.all_cpp.files libmpc_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libmpc_la.all_cpp.final; \ + for file in mpcfile.cpp mpcproperties.cpp ; do \ + echo "#include \"$$file\"" >> libmpc_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libmpc_la.all_cpp.final; \ + done; \ + cat libmpc_la.all_cpp.final libmpc_la.all_cpp.files > libmpc_la.all_cpp.cpp; \ + rm -f libmpc_la.all_cpp.final libmpc_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libmpc_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libmpc_la_OBJECTS="$(libmpc_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libmpc_la_OBJECTS="$(libmpc_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libmpc_la_OBJECTS="$(libmpc_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libmpc_la_OBJECTS="$(libmpc_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/mpc/combinedtag.h b/Libraries/TagLib/Files/taglib/mpc/combinedtag.h new file mode 100644 index 000000000..c2a199821 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpc/combinedtag.h @@ -0,0 +1,171 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef DO_NOT_DOCUMENT // Tell Doxygen not to document this header + +#ifndef TAGLIB_COMBINEDTAG_H +#define TAGLIB_COMBINEDTAG_H + +//////////////////////////////////////////////////////////////////////////////// +// Note that this header is not installed. +//////////////////////////////////////////////////////////////////////////////// + +#include + +namespace TagLib { + + /*! + * A union of two TagLib::Tags. + */ + class CombinedTag : public TagLib::Tag + { + public: + CombinedTag(Tag *tag1 = 0, Tag *tag2 = 0) + : TagLib::Tag(), + tag1(tag1), tag2(tag2) {} + + virtual String title() const { + if(tag1 && !tag1->title().isEmpty()) + return tag1->title(); + + if(tag2) + return tag2->title(); + + return String::null; + } + + virtual String artist() const { + if(tag1 && !tag1->artist().isEmpty()) + return tag1->artist(); + + if(tag2) + return tag2->artist(); + + return String::null; + } + + virtual String album() const { + if(tag1 && !tag1->album().isEmpty()) + return tag1->album(); + + if(tag2) + return tag2->album(); + + return String::null; + } + + virtual String comment() const { + if(tag1 && !tag1->comment().isEmpty()) + return tag1->comment(); + + if(tag2) + return tag2->comment(); + + return String::null; + } + + virtual String genre() const { + if(tag1 && !tag1->genre().isEmpty()) + return tag1->genre(); + + if(tag2) + return tag2->genre(); + + return String::null; + } + + virtual uint year() const { + if(tag1 && tag1->year() > 0) + return tag1->year(); + + if(tag2) + return tag2->year(); + + return 0; + } + + virtual uint track() const { + if(tag1 && tag1->track() > 0) + return tag1->track(); + + if(tag2) + return tag2->track(); + + return 0; + } + + virtual void setTitle(const String &s) { + if(tag1) + tag1->setTitle(s); + if(tag2) + tag2->setTitle(s); + } + + virtual void setArtist(const String &s) { + if(tag1) + tag1->setArtist(s); + if(tag2) + tag2->setArtist(s); + } + + virtual void setAlbum(const String &s) { + if(tag1) + tag1->setAlbum(s); + if(tag2) + tag2->setAlbum(s); + } + + virtual void setComment(const String &s) { + if(tag1) + tag1->setComment(s); + if(tag2) + tag2->setComment(s); + } + + virtual void setGenre(const String &s) { + if(tag1) + tag1->setGenre(s); + if(tag2) + tag2->setGenre(s); + } + + virtual void setYear(uint i) { + if(tag1) + tag1->setYear(i); + if(tag2) + tag2->setYear(i); + } + + virtual void setTrack(uint i) { + if(tag1) + tag1->setTrack(i); + if(tag2) + tag2->setTrack(i); + } + + private: + Tag *tag1; + Tag *tag2; + }; +} + +#endif +#endif diff --git a/Libraries/TagLib/Files/taglib/mpc/mpcfile.cpp b/Libraries/TagLib/Files/taglib/mpc/mpcfile.cpp new file mode 100644 index 000000000..ae77e37b2 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpc/mpcfile.cpp @@ -0,0 +1,358 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include + +#include "mpcfile.h" +#include "id3v1tag.h" +#include "id3v2header.h" +#include "apetag.h" +#include "apefooter.h" +#include "combinedtag.h" + +using namespace TagLib; + +class MPC::File::FilePrivate +{ +public: + FilePrivate() : + APETag(0), + APELocation(-1), + APESize(0), + ID3v1Tag(0), + ID3v1Location(-1), + ID3v2Header(0), + ID3v2Location(-1), + ID3v2Size(0), + tag(0), + properties(0), + scanned(false), + hasAPE(false), + hasID3v1(false), + hasID3v2(false) {} + + ~FilePrivate() + { + delete ID3v1Tag; + delete properties; + } + + APE::Tag *APETag; + // long APEFooter; + long APELocation; + uint APESize; + + ID3v1::Tag *ID3v1Tag; + long ID3v1Location; + + ID3v2::Header *ID3v2Header; + long ID3v2Location; + uint ID3v2Size; + + Tag *tag; + + Properties *properties; + bool scanned; + + // These indicate whether the file *on disk* has these tags, not if + // this data structure does. This is used in computing offsets. + + bool hasAPE; + bool hasID3v1; + bool hasID3v2; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MPC::File::File(const char *file, bool readProperties, + Properties::ReadStyle propertiesStyle) : TagLib::File(file) +{ + d = new FilePrivate; + read(readProperties, propertiesStyle); +} + +MPC::File::~File() +{ + delete d; +} + +TagLib::Tag *MPC::File::tag() const +{ + return d->tag; +} + +MPC::Properties *MPC::File::audioProperties() const +{ + return d->properties; +} + +bool MPC::File::save() +{ + if(readOnly()) { + debug("MPC::File::save() -- File is read only."); + return false; + } + + // Possibly strip ID3v2 tag + + if(d->hasID3v2 && !d->ID3v2Header) { + removeBlock(d->ID3v2Location, d->ID3v2Size); + d->hasID3v2 = false; + if(d->hasID3v1) + d->ID3v1Location -= d->ID3v2Size; + if(d->hasAPE) + d->APELocation -= d->ID3v2Size; + } + + // Update ID3v1 tag + + if(d->ID3v1Tag) { + if(d->hasID3v1) { + seek(d->ID3v1Location); + writeBlock(d->ID3v1Tag->render()); + } + else { + seek(0, End); + d->ID3v1Location = tell(); + writeBlock(d->ID3v1Tag->render()); + d->hasID3v1 = true; + } + } else + if(d->hasID3v1) { + removeBlock(d->ID3v1Location, 128); + d->hasID3v1 = false; + if(d->hasAPE) { + if(d->APELocation > d->ID3v1Location) + d->APELocation -= 128; + } + } + + // Update APE tag + + if(d->APETag) { + if(d->hasAPE) + insert(d->APETag->render(), d->APELocation, d->APESize); + else { + if(d->hasID3v1) { + insert(d->APETag->render(), d->ID3v1Location, 0); + d->APESize = d->APETag->footer()->completeTagSize(); + d->hasAPE = true; + d->APELocation = d->ID3v1Location; + d->ID3v1Location += d->APESize; + } + else { + seek(0, End); + d->APELocation = tell(); + writeBlock(d->APETag->render()); + d->APESize = d->APETag->footer()->completeTagSize(); + d->hasAPE = true; + } + } + } + else + if(d->hasAPE) { + removeBlock(d->APELocation, d->APESize); + d->hasAPE = false; + if(d->hasID3v1) { + if (d->ID3v1Location > d->APELocation) + d->ID3v1Location -= d->APESize; + } + } + + return true; +} + +ID3v1::Tag *MPC::File::ID3v1Tag(bool create) +{ + if(!create || d->ID3v1Tag) + return d->ID3v1Tag; + + // no ID3v1 tag exists and we've been asked to create one + + d->ID3v1Tag = new ID3v1::Tag; + + if(d->APETag) + d->tag = new CombinedTag(d->APETag, d->ID3v1Tag); + else + d->tag = d->ID3v1Tag; + + return d->ID3v1Tag; +} + +APE::Tag *MPC::File::APETag(bool create) +{ + if(!create || d->APETag) + return d->APETag; + + // no APE tag exists and we've been asked to create one + + d->APETag = new APE::Tag; + + if(d->ID3v1Tag) + d->tag = new CombinedTag(d->APETag, d->ID3v1Tag); + else + d->tag = d->APETag; + + return d->APETag; +} + +void MPC::File::remove(int tags) +{ + if(tags & ID3v1) { + delete d->ID3v1Tag; + d->ID3v1Tag = 0; + + if(d->APETag) + d->tag = d->APETag; + else + d->tag = d->APETag = new APE::Tag(); + } + + if(tags & ID3v2) { + delete d->ID3v2Header; + d->ID3v2Header = 0; + } + + if(tags & APE) { + delete d->APETag; + d->APETag = 0; + + if(d->ID3v1Tag) + d->tag = d->ID3v1Tag; + else + d->tag = d->APETag = new APE::Tag(); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) +{ + // Look for an ID3v1 tag + + d->ID3v1Location = findID3v1(); + + if(d->ID3v1Location >= 0) { + d->ID3v1Tag = new ID3v1::Tag(this, d->ID3v1Location); + d->hasID3v1 = true; + } + + // Look for an APE tag + + findAPE(); + + d->APELocation = findAPE(); + + if(d->APELocation >= 0) { + d->APETag = new APE::Tag(this, d->APELocation); + d->APESize = d->APETag->footer()->completeTagSize(); + d->APELocation = d->APELocation + d->APETag->footer()->size() - d->APESize; + d->hasAPE = true; + } + + if(d->hasID3v1 && d->hasAPE) + d->tag = new CombinedTag(d->APETag, d->ID3v1Tag); + else { + if(d->hasID3v1) + d->tag = d->ID3v1Tag; + else { + if(d->hasAPE) + d->tag = d->APETag; + else + d->tag = d->APETag = new APE::Tag(); + } + } + + // Look for and skip an ID3v2 tag + + d->ID3v2Location = findID3v2(); + + if(d->ID3v2Location >= 0) { + seek(d->ID3v2Location); + d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); + d->ID3v2Size = d->ID3v2Header->completeTagSize(); + d->hasID3v2 = true; + } + + if(d->hasID3v2) + seek(d->ID3v2Location + d->ID3v2Size); + else + seek(0); + + // Look for MPC metadata + + if(readProperties) { + d->properties = new Properties(readBlock(MPC::HeaderSize), + length() - d->ID3v2Size - d->APESize); + } +} + +long MPC::File::findAPE() +{ + if(!isValid()) + return -1; + + if(d->hasID3v1) + seek(-160, End); + else + seek(-32, End); + + long p = tell(); + + if(readBlock(8) == APE::Tag::fileIdentifier()) + return p; + + return -1; +} + +long MPC::File::findID3v1() +{ + if(!isValid()) + return -1; + + seek(-128, End); + long p = tell(); + + if(readBlock(3) == ID3v1::Tag::fileIdentifier()) + return p; + + return -1; +} + +long MPC::File::findID3v2() +{ + if(!isValid()) + return -1; + + seek(0); + + if(readBlock(3) == ID3v2::Header::fileIdentifier()) + return 0; + + return -1; +} diff --git a/Libraries/TagLib/Files/taglib/mpc/mpcfile.h b/Libraries/TagLib/Files/taglib/mpc/mpcfile.h new file mode 100644 index 000000000..aa40e953f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpc/mpcfile.h @@ -0,0 +1,162 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_MPCFILE_H +#define TAGLIB_MPCFILE_H + +#include "tfile.h" + +#include "mpcproperties.h" + +namespace TagLib { + + class Tag; + + namespace ID3v1 { class Tag; } + namespace APE { class Tag; } + + //! An implementation of MPC metadata + + /*! + * This is implementation of MPC metadata. + * + * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream + * properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped + * and ignored. + */ + + namespace MPC { + + //! An implementation of TagLib::File with MPC specific methods + + /*! + * This implements and provides an interface for MPC files to the + * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing + * the abstract TagLib::File API as well as providing some additional + * information specific to MPC files. + * The only invalid tag combination supported is an ID3v1 tag after an APE tag. + */ + + class File : public TagLib::File + { + public: + /*! + * This set of flags is used for various operations and is suitable for + * being OR-ed together. + */ + enum TagTypes { + //! Empty set. Matches no tag types. + NoTags = 0x0000, + //! Matches ID3v1 tags. + ID3v1 = 0x0001, + //! Matches ID3v2 tags. + ID3v2 = 0x0002, + //! Matches APE tags. + APE = 0x0004, + //! Matches all tag types. + AllTags = 0xffff + }; + + /*! + * Contructs an MPC file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + */ + File(const char *file, bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns the Tag for this file. This will be an APE tag, an ID3v1 tag + * or a combination of the two. + */ + virtual TagLib::Tag *tag() const; + + /*! + * Returns the MPC::Properties for this file. If no audio properties + * were read then this will return a null pointer. + */ + virtual Properties *audioProperties() const; + + /*! + * Saves the file. + */ + virtual bool save(); + + /*! + * Returns a pointer to the ID3v1 tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid ID3v1 tag. If \a create is true it will create + * an ID3v1 tag if one does not exist. If there is already an APE tag, the + * new ID3v1 tag will be placed after it. + * + * \note The Tag is still owned by the APE::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + ID3v1::Tag *ID3v1Tag(bool create = false); + + /*! + * Returns a pointer to the APE tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid APE tag. If \a create is true it will create + * a APE tag if one does not exist. If there is already an ID3v1 tag, thes + * new APE tag will be placed before it. + * + * \note The Tag is still owned by the APE::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + APE::Tag *APETag(bool create = false); + + /*! + * This will remove the tags that match the OR-ed together TagTypes from the + * file. By default it removes all tags. + * + * \note This will also invalidate pointers to the tags + * as their memory will be freed. + * \note In order to make the removal permanent save() still needs to be called + */ + void remove(int tags = AllTags); + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + void scan(); + long findAPE(); + long findID3v1(); + long findID3v2(); + + class FilePrivate; + FilePrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpc/mpcproperties.cpp b/Libraries/TagLib/Files/taglib/mpc/mpcproperties.cpp new file mode 100644 index 000000000..fb61b244d --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpc/mpcproperties.cpp @@ -0,0 +1,140 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include + +#include "mpcproperties.h" +#include "mpcfile.h" + +using namespace TagLib; + +class MPC::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) : + data(d), + streamLength(length), + style(s), + version(0), + length(0), + bitrate(0), + sampleRate(0), + channels(0) {} + + ByteVector data; + long streamLength; + ReadStyle style; + int version; + int length; + int bitrate; + int sampleRate; + int channels; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) +{ + d = new PropertiesPrivate(data, streamLength, style); + read(); +} + +MPC::Properties::~Properties() +{ + delete d; +} + +int MPC::Properties::length() const +{ + return d->length; +} + +int MPC::Properties::bitrate() const +{ + return d->bitrate; +} + +int MPC::Properties::sampleRate() const +{ + return d->sampleRate; +} + +/* +int MPC::Properties::sampleWidth() const +{ + return d->sampleWidth; +} +*/ + +int MPC::Properties::channels() const +{ + return d->channels; +} + +int MPC::Properties::mpcVersion() const +{ + return d->version; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 }; + +void MPC::Properties::read() +{ + if(d->data.mid(0, 3) != "MP+") + return; + + d->version = d->data[3] & 15; + + unsigned int frames; + + if(d->version >= 7) { + frames = d->data.mid(4, 4).toUInt(false); + + std::bitset<32> flags = d->data.mid(8, 4).toUInt(true); + d->sampleRate = sftable[flags[17] * 2 + flags[16]]; + d->channels = 2; + } + else { + unsigned int headerData = d->data.mid(0, 4).toUInt(false); + d->bitrate = (headerData >> 23) & 0x01ff; + d->version = (headerData >> 11) & 0x03ff; + d->sampleRate = 44100; + d->channels = 2; + if(d->version >= 5) + frames = d->data.mid(4, 4).toUInt(false); + else + frames = d->data.mid(4, 2).toUInt(false); + } + + unsigned int samples = frames * 1152 - 576; + d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0; + + if(!d->bitrate) + d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; +} diff --git a/Libraries/TagLib/Files/taglib/mpc/mpcproperties.h b/Libraries/TagLib/Files/taglib/mpc/mpcproperties.h new file mode 100644 index 000000000..4febde4db --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpc/mpcproperties.h @@ -0,0 +1,77 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_MPCPROPERTIES_H +#define TAGLIB_MPCPROPERTIES_H + +#include "audioproperties.h" + +namespace TagLib { + + namespace MPC { + + class File; + + static const uint HeaderSize = 8*7; + + //! An implementation of audio property reading for MPC + + /*! + * This reads the data from an MPC stream found in the AudioProperties + * API. + */ + + class Properties : public AudioProperties + { + public: + /*! + * Create an instance of MPC::Properties with the data read from the + * ByteVector \a data. + */ + Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); + + /*! + * Destroys this MPC::Properties instance. + */ + virtual ~Properties(); + + // Reimplementations. + + virtual int length() const; + virtual int bitrate() const; + virtual int sampleRate() const; + virtual int channels() const; + + /*! + * Returns the version of the bitstream (SV4-SV7) + */ + int mpcVersion() const; + + private: + void read(); + + class PropertiesPrivate; + PropertiesPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/Makefile.am b/Libraries/TagLib/Files/taglib/mpeg/Makefile.am new file mode 100644 index 000000000..acc3614ea --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/Makefile.am @@ -0,0 +1,19 @@ +SUBDIRS = id3v1 id3v2 +INCLUDES = \ + -I$(top_srcdir)/taglib\ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ape \ + -I$(top_srcdir)/taglib/mpeg/id3v2 -I./id3v2 \ + -I$(top_srcdir)/taglib/mpeg/id3v1 -I./id3v1 \ + $(all_includes) + +noinst_LTLIBRARIES = libmpeg.la + +libmpeg_la_SOURCES = mpegfile.cpp mpegproperties.cpp mpegheader.cpp xingheader.cpp + +taglib_include_HEADERS = mpegfile.h mpegproperties.h mpegheader.h xingheader.h +taglib_includedir = $(includedir)/taglib + +libmpeg_la_LIBADD = ./id3v2/libid3v2.la ./id3v1/libid3v1.la + +EXTRA_DIST = $(libmpeg_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/mpeg/Makefile.in b/Libraries/TagLib/Files/taglib/mpeg/Makefile.in new file mode 100644 index 000000000..93049f13c --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/Makefile.in @@ -0,0 +1,662 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +SUBDIRS = id3v1 id3v2 +INCLUDES = \ + -I$(top_srcdir)/taglib\ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ape \ + -I$(top_srcdir)/taglib/mpeg/id3v2 -I./id3v2 \ + -I$(top_srcdir)/taglib/mpeg/id3v1 -I./id3v1 \ + $(all_includes) + + +noinst_LTLIBRARIES = libmpeg.la + +libmpeg_la_SOURCES = mpegfile.cpp mpegproperties.cpp mpegheader.cpp xingheader.cpp + +taglib_include_HEADERS = mpegfile.h mpegproperties.h mpegheader.h xingheader.h +taglib_includedir = $(includedir)/taglib + +libmpeg_la_LIBADD = ./id3v2/libid3v2.la ./id3v1/libid3v1.la + +EXTRA_DIST = $(libmpeg_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/mpeg +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libmpeg_la_LDFLAGS = +libmpeg_la_DEPENDENCIES = ./id3v2/libid3v2.la ./id3v1/libid3v1.la +am_libmpeg_la_OBJECTS = mpegfile.lo mpegproperties.lo mpegheader.lo \ + xingheader.lo +#>- libmpeg_la_OBJECTS = $(am_libmpeg_la_OBJECTS) +#>+ 5 +libmpeg_la_final_OBJECTS = libmpeg_la.all_cpp.lo +libmpeg_la_nofinal_OBJECTS = mpegfile.lo mpegproperties.lo mpegheader.lo \ + xingheader.lo +@KDE_USE_FINAL_FALSE@libmpeg_la_OBJECTS = $(libmpeg_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libmpeg_la_OBJECTS = $(libmpeg_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/mpegfile.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/mpegheader.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/mpegproperties.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/xingheader.Plo +#>+ 9 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libmpeg_la.all_cpp.P ./$(DEPDIR)/mpegfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/mpegheader.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/mpegproperties.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/xingheader.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/mpegfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/mpegheader.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/mpegproperties.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/xingheader.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libmpeg_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + + +RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ + ps-recursive install-info-recursive uninstall-info-recursive \ + all-recursive install-data-recursive install-exec-recursive \ + installdirs-recursive install-recursive uninstall-recursive \ + check-recursive installcheck-recursive +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +DIST_SUBDIRS = $(SUBDIRS) +SOURCES = $(libmpeg_la_SOURCES) + +#>- all: all-recursive +#>+ 1 +all: docs-am all-recursive + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/mpeg/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmpeg.la: $(libmpeg_la_OBJECTS) $(libmpeg_la_DEPENDENCIES) + $(CXXLINK) $(libmpeg_la_LDFLAGS) $(libmpeg_la_OBJECTS) $(libmpeg_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpegfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpegheader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpegproperties.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xingheader.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + 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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: ctags-recursive $(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 +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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-recursive +#>+ 1 +clean: kde-rpo-clean clean-recursive + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-taglib_includeHEADERS + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-recursive distclean-tags distdir \ + dvi dvi-am dvi-recursive info info-am info-recursive install \ + install-am install-data install-data-am install-data-recursive \ + install-exec install-exec-am install-exec-recursive \ + install-info install-info-am install-info-recursive install-man \ + install-recursive install-strip install-taglib_includeHEADERS \ + installcheck installcheck-am installdirs installdirs-am \ + installdirs-recursive maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ + pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ + tags-recursive uninstall uninstall-am uninstall-info-am \ + uninstall-info-recursive uninstall-recursive \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/Makefile.in + + +#>+ 11 +libmpeg_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/mpegfile.cpp $(srcdir)/mpegproperties.cpp $(srcdir)/mpegheader.cpp $(srcdir)/xingheader.cpp + @echo 'creating libmpeg_la.all_cpp.cpp ...'; \ + rm -f libmpeg_la.all_cpp.files libmpeg_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libmpeg_la.all_cpp.final; \ + for file in mpegfile.cpp mpegproperties.cpp mpegheader.cpp xingheader.cpp ; do \ + echo "#include \"$$file\"" >> libmpeg_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libmpeg_la.all_cpp.final; \ + done; \ + cat libmpeg_la.all_cpp.final libmpeg_la.all_cpp.files > libmpeg_la.all_cpp.cpp; \ + rm -f libmpeg_la.all_cpp.final libmpeg_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libmpeg_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libmpeg_la_OBJECTS="$(libmpeg_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libmpeg_la_OBJECTS="$(libmpeg_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libmpeg_la_OBJECTS="$(libmpeg_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libmpeg_la_OBJECTS="$(libmpeg_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v1/Makefile.am b/Libraries/TagLib/Files/taglib/mpeg/id3v1/Makefile.am new file mode 100644 index 000000000..ae0b590a1 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v1/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/mpeg \ + $(all_includes) + +noinst_LTLIBRARIES = libid3v1.la + +libid3v1_la_SOURCES = id3v1tag.cpp id3v1genres.cpp + +taglib_include_HEADERS = id3v1tag.h id3v1genres.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libid3v1_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v1/Makefile.in b/Libraries/TagLib/Files/taglib/mpeg/id3v1/Makefile.in new file mode 100644 index 000000000..4355d3a26 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v1/Makefile.in @@ -0,0 +1,548 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/mpeg \ + $(all_includes) + + +noinst_LTLIBRARIES = libid3v1.la + +libid3v1_la_SOURCES = id3v1tag.cpp id3v1genres.cpp + +taglib_include_HEADERS = id3v1tag.h id3v1genres.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libid3v1_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/mpeg/id3v1 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libid3v1_la_LDFLAGS = +libid3v1_la_LIBADD = +am_libid3v1_la_OBJECTS = id3v1tag.lo id3v1genres.lo +#>- libid3v1_la_OBJECTS = $(am_libid3v1_la_OBJECTS) +#>+ 4 +libid3v1_la_final_OBJECTS = libid3v1_la.all_cpp.lo +libid3v1_la_nofinal_OBJECTS = id3v1tag.lo id3v1genres.lo +@KDE_USE_FINAL_FALSE@libid3v1_la_OBJECTS = $(libid3v1_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libid3v1_la_OBJECTS = $(libid3v1_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/id3v1genres.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/id3v1tag.Plo +#>+ 5 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libid3v1_la.all_cpp.P ./$(DEPDIR)/id3v1genres.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v1tag.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/id3v1genres.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v1tag.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libid3v1_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(libid3v1_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/mpeg/id3v1/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/id3v1/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/id3v1/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libid3v1.la: $(libid3v1_la_OBJECTS) $(libid3v1_la_DEPENDENCIES) + $(CXXLINK) $(libid3v1_la_LDFLAGS) $(libid3v1_la_OBJECTS) $(libid3v1_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v1genres.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v1tag.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/id3v1/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/id3v1/Makefile.in + + +#>+ 11 +libid3v1_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/id3v1tag.cpp $(srcdir)/id3v1genres.cpp + @echo 'creating libid3v1_la.all_cpp.cpp ...'; \ + rm -f libid3v1_la.all_cpp.files libid3v1_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libid3v1_la.all_cpp.final; \ + for file in id3v1tag.cpp id3v1genres.cpp ; do \ + echo "#include \"$$file\"" >> libid3v1_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libid3v1_la.all_cpp.final; \ + done; \ + cat libid3v1_la.all_cpp.final libid3v1_la.all_cpp.files > libid3v1_la.all_cpp.cpp; \ + rm -f libid3v1_la.all_cpp.final libid3v1_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libid3v1_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libid3v1_la_OBJECTS="$(libid3v1_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libid3v1_la_OBJECTS="$(libid3v1_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libid3v1_la_OBJECTS="$(libid3v1_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libid3v1_la_OBJECTS="$(libid3v1_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1genres.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1genres.cpp new file mode 100644 index 000000000..0f4fd4382 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1genres.cpp @@ -0,0 +1,215 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org +***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "id3v1genres.h" + +using namespace TagLib; + +namespace TagLib { + namespace ID3v1 { + + static const int genresSize = 148; + static const String genres[] = { + "Blues", + "Classic Rock", + "Country", + "Dance", + "Disco", + "Funk", + "Grunge", + "Hip-Hop", + "Jazz", + "Metal", + "New Age", + "Oldies", + "Other", + "Pop", + "R&B", + "Rap", + "Reggae", + "Rock", + "Techno", + "Industrial", + "Alternative", + "Ska", + "Death Metal", + "Pranks", + "Soundtrack", + "Euro-Techno", + "Ambient", + "Trip-Hop", + "Vocal", + "Jazz+Funk", + "Fusion", + "Trance", + "Classical", + "Instrumental", + "Acid", + "House", + "Game", + "Sound Clip", + "Gospel", + "Noise", + "Alternative Rock", + "Bass", + "Soul", + "Punk", + "Space", + "Meditative", + "Instrumental Pop", + "Instrumental Rock", + "Ethnic", + "Gothic", + "Darkwave", + "Techno-Industrial", + "Electronic", + "Pop-Folk", + "Eurodance", + "Dream", + "Southern Rock", + "Comedy", + "Cult", + "Gangsta", + "Top 40", + "Christian Rap", + "Pop/Funk", + "Jungle", + "Native American", + "Cabaret", + "New Wave", + "Psychedelic", + "Rave", + "Showtunes", + "Trailer", + "Lo-Fi", + "Tribal", + "Acid Punk", + "Acid Jazz", + "Polka", + "Retro", + "Musical", + "Rock & Roll", + "Hard Rock", + "Folk", + "Folk/Rock", + "National Folk", + "Swing", + "Fusion", + "Bebob", + "Latin", + "Revival", + "Celtic", + "Bluegrass", + "Avantgarde", + "Gothic Rock", + "Progressive Rock", + "Psychedelic Rock", + "Symphonic Rock", + "Slow Rock", + "Big Band", + "Chorus", + "Easy Listening", + "Acoustic", + "Humour", + "Speech", + "Chanson", + "Opera", + "Chamber Music", + "Sonata", + "Symphony", + "Booty Bass", + "Primus", + "Porn Groove", + "Satire", + "Slow Jam", + "Club", + "Tango", + "Samba", + "Folklore", + "Ballad", + "Power Ballad", + "Rhythmic Soul", + "Freestyle", + "Duet", + "Punk Rock", + "Drum Solo", + "A Capella", + "Euro-House", + "Dance Hall", + "Goa", + "Drum & Bass", + "Club-House", + "Hardcore", + "Terror", + "Indie", + "BritPop", + "Negerpunk", + "Polsk Punk", + "Beat", + "Christian Gangsta Rap", + "Heavy Metal", + "Black Metal", + "Crossover", + "Contemporary Christian", + "Christian Rock", + "Merengue", + "Salsa", + "Thrash Metal", + "Anime", + "Jpop", + "Synthpop" + }; + } +} + +StringList ID3v1::genreList() +{ + static StringList l; + if(l.isEmpty()) { + for(int i = 0; i < genresSize; i++) + l.append(genres[i]); + } + return l; +} + +ID3v1::GenreMap ID3v1::genreMap() +{ + static GenreMap m; + if(m.isEmpty()) { + for(int i = 0; i < genresSize; i++) + m.insert(genres[i], i); + } + return m; +} + +String ID3v1::genre(int i) +{ + if(i >= 0 && i < genresSize) + return genres[i]; + return String::null; +} + +int ID3v1::genreIndex(const String &name) +{ + if(genreMap().contains(name)) + return genreMap()[name]; + return 255; +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1genres.h b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1genres.h new file mode 100644 index 000000000..97caee8ac --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1genres.h @@ -0,0 +1,61 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V1GENRE_H +#define TAGLIB_ID3V1GENRE_H + +#include +#include + +namespace TagLib { + namespace ID3v1 { + + typedef Map GenreMap; + + /*! + * Returns the list of canonical ID3v1 genre names in the order that they + * are listed in the standard. + */ + StringList genreList(); + + /*! + * A "reverse mapping" that goes from the canonical ID3v1 genre name to the + * respective genre number. genreMap()["Rock"] == + */ + GenreMap genreMap(); + + /*! + * Returns the name of the genre at \a index in the ID3v1 genre list. If + * \a index is out of range -- less than zero or greater than 146 -- a null + * string will be returned. + */ + String genre(int index); + + /*! + * Returns the genre index for the (case sensitive) genre \a name. If the + * genre is not in the list 255 (which signifies an unknown genre in ID3v1) + * will be returned. + */ + int genreIndex(const String &name); + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1tag.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1tag.cpp new file mode 100644 index 000000000..2e7233eb2 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1tag.cpp @@ -0,0 +1,256 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "id3v1tag.h" +#include "id3v1genres.h" + +using namespace TagLib; +using namespace ID3v1; + +class ID3v1::Tag::TagPrivate +{ +public: + TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {} + + File *file; + long tagOffset; + + String title; + String artist; + String album; + String year; + String comment; + uchar track; + uchar genre; + + static const StringHandler *stringHandler; +}; + +const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = new StringHandler; + +//////////////////////////////////////////////////////////////////////////////// +// StringHandler implementation +//////////////////////////////////////////////////////////////////////////////// + +String ID3v1::StringHandler::parse(const ByteVector &data) const +{ + return clean(String(data, String::Latin1)); +} + +ByteVector ID3v1::StringHandler::render(const String &s) const +{ + return s.data(String::Latin1); +} + +String ID3v1::StringHandler::clean(const String &s) const +{ + String newString; + int i; + + newString = s; + + i = newString.size() - 1; + while (s[i] == ' ' && i >= 0) + { + newString[i] = '\0'; + i--; + } + + return newString; +} + +//////////////////////////////////////////////////////////////////////////////// +// public methods +//////////////////////////////////////////////////////////////////////////////// + +ID3v1::Tag::Tag() : TagLib::Tag() +{ + d = new TagPrivate; +} + +ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag() +{ + d = new TagPrivate; + d->file = file; + d->tagOffset = tagOffset; + + read(); +} + +ID3v1::Tag::~Tag() +{ + delete d; +} + +ByteVector ID3v1::Tag::render() const +{ + ByteVector data; + + data.append(fileIdentifier()); + data.append(TagPrivate::stringHandler->render(d->title).resize(30)); + data.append(TagPrivate::stringHandler->render(d->artist).resize(30)); + data.append(TagPrivate::stringHandler->render(d->album).resize(30)); + data.append(TagPrivate::stringHandler->render(d->year).resize(4)); + data.append(TagPrivate::stringHandler->render(d->comment).resize(28)); + data.append(char(0)); + data.append(char(d->track)); + data.append(char(d->genre)); + + return data; +} + +ByteVector ID3v1::Tag::fileIdentifier() +{ + return ByteVector::fromCString("TAG"); +} + +String ID3v1::Tag::title() const +{ + return d->title; +} + +String ID3v1::Tag::artist() const +{ + return d->artist; +} + +String ID3v1::Tag::album() const +{ + return d->album; +} + +String ID3v1::Tag::comment() const +{ + return d->comment; +} + +String ID3v1::Tag::genre() const +{ + return ID3v1::genre(d->genre); +} + +TagLib::uint ID3v1::Tag::year() const +{ + return d->year.toInt(); +} + +TagLib::uint ID3v1::Tag::track() const +{ + return d->track; +} + +void ID3v1::Tag::setTitle(const String &s) +{ + d->title = s; +} + +void ID3v1::Tag::setArtist(const String &s) +{ + d->artist = s; +} + +void ID3v1::Tag::setAlbum(const String &s) +{ + d->album = s; +} + +void ID3v1::Tag::setComment(const String &s) +{ + d->comment = s; +} + +void ID3v1::Tag::setGenre(const String &s) +{ + d->genre = ID3v1::genreIndex(s); +} + +void ID3v1::Tag::setYear(uint i) +{ + d->year = String::number(i); +} + +void ID3v1::Tag::setTrack(uint i) +{ + d->track = i < 256 ? i : 0; +} + +void ID3v1::Tag::setStringHandler(const StringHandler *handler) +{ + delete TagPrivate::stringHandler; + TagPrivate::stringHandler = handler; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected methods +//////////////////////////////////////////////////////////////////////////////// + +void ID3v1::Tag::read() +{ + if(d->file && d->file->isValid()) { + d->file->seek(d->tagOffset); + // read the tag -- always 128 bytes + ByteVector data = d->file->readBlock(128); + + // some initial sanity checking + if(data.size() == 128 && data.mid(0, 3) == "TAG") + parse(data); + else + debug("ID3v1 tag is not valid or could not be read at the specified offset."); + } +} + +void ID3v1::Tag::parse(const ByteVector &data) +{ + int offset = 3; + + d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + offset += 30; + + d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + offset += 30; + + d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30)); + offset += 30; + + d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4)); + offset += 4; + + // Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this + // is not a bug in TagLib. Since a zeroed byte is what we would expect to + // indicate the end of a C-String, specifically the comment string, a value of + // zero must be assumed to be just that. + + if(data[offset + 28] == 0 && data[offset + 29] != 0) { + // ID3v1.1 detected + + d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28)); + d->track = uchar(data[offset + 29]); + } + else + d->comment = data.mid(offset, 30); + + offset += 30; + + d->genre = uchar(data[offset]); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1tag.h b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1tag.h new file mode 100644 index 000000000..3c474dcb5 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v1/id3v1tag.h @@ -0,0 +1,176 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V1TAG_H +#define TAGLIB_ID3V1TAG_H + +#include +#include + +namespace TagLib { + + class File; + + //! An ID3v1 implementation + + namespace ID3v1 { + + //! A abstraction for the string to data encoding in ID3v1 tags. + + /*! + * ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In + * practice it does not. TagLib by default only supports ISO-8859-1 data + * in ID3v1 tags. + * + * However by subclassing this class and reimplementing parse() and render() + * and setting your reimplementation as the default with + * ID3v1::Tag::setStringHandler() you can define how you would like these + * transformations to be done. + * + * \warning It is advisable not to write non-ISO-8859-1 data to ID3v1 + * tags. Please consider disabling the writing of ID3v1 tags in the case + * that the data is ISO-8859-1. + * + * \see ID3v1::Tag::setStringHandler() + */ + + class StringHandler + { + public: + /*! + * Decode a string from \a data. The default implementation assumes that + * \a data is an ISO-8859-1 (Latin1) character array. + */ + virtual String parse(const ByteVector &data) const; + + /*! + * Encode a ByteVector with the data from \a s. The default implementation + * assumes that \a s is an ISO-8859-1 (Latin1) string. + * + * \warning It is recommended that you not override this method, but + * instead do not write an ID3v1 tag in the case that the data is not + * ISO-8859-1. + */ + virtual ByteVector render(const String &s) const; + + + //Fixes buggy taggers which do spaces instead of 0s. + String ID3v1::StringHandler::clean(const String &s) const; + }; + + //! The main class in the ID3v1 implementation + + /*! + * This is an implementation of the ID3v1 format. ID3v1 is both the simplist + * and most common of tag formats but is rather limited. Because of its + * pervasiveness and the way that applications have been written around the + * fields that it provides, the generic TagLib::Tag API is a mirror of what is + * provided by ID3v1. + * + * ID3v1 tags should generally only contain Latin1 information. However because + * many applications do not follow this rule there is now support for overriding + * the ID3v1 string handling using the ID3v1::StringHandler class. Please see + * the documentation for that class for more information. + * + * \see StringHandler + * + * \note Most fields are truncated to a maximum of 28-30 bytes. The + * truncation happens automatically when the tag is rendered. + */ + + class Tag : public TagLib::Tag + { + public: + /*! + * Create an ID3v1 tag with default values. + */ + Tag(); + + /*! + * Create an ID3v1 tag and parse the data in \a file starting at + * \a tagOffset. + */ + Tag(File *file, long tagOffset); + + /*! + * Destroys this Tag instance. + */ + virtual ~Tag(); + + /*! + * Renders the in memory values to a ByteVector suitable for writing to + * the file. + */ + ByteVector render() const; + + /*! + * Returns the string "TAG" suitable for usage in locating the tag in a + * file. + */ + static ByteVector fileIdentifier(); + + // Reimplementations. + + virtual String title() const; + virtual String artist() const; + virtual String album() const; + virtual String comment() const; + virtual String genre() const; + virtual uint year() const; + virtual uint track() const; + + virtual void setTitle(const String &s); + virtual void setArtist(const String &s); + virtual void setAlbum(const String &s); + virtual void setComment(const String &s); + virtual void setGenre(const String &s); + virtual void setYear(uint i); + virtual void setTrack(uint i); + + /*! + * Sets the string handler that decides how the ID3v1 data will be + * converted to and from binary data. + * + * \see StringHandler + */ + static void setStringHandler(const StringHandler *handler); + + protected: + /*! + * Reads from the file specified in the constructor. + */ + void read(); + /*! + * Pareses the body of the tag in \a data. + */ + void parse(const ByteVector &data); + + private: + Tag(const Tag &); + Tag &operator=(const Tag &); + + class TagPrivate; + TagPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/Makefile.am b/Libraries/TagLib/Files/taglib/mpeg/id3v2/Makefile.am new file mode 100644 index 000000000..a58c83e95 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/Makefile.am @@ -0,0 +1,28 @@ +SUBDIRS = frames +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/mpeg \ + -I$(top_srcdir)/taglib/mpeg/id3v1 \ + $(all_includes) + +noinst_LTLIBRARIES = libid3v2.la + +libid3v2_la_SOURCES = \ + id3v2framefactory.cpp id3v2synchdata.cpp id3v2tag.cpp \ + id3v2header.cpp id3v2frame.cpp id3v2footer.cpp \ + id3v2extendedheader.cpp + +taglib_include_HEADERS = \ + id3v2extendedheader.h id3v2frame.h id3v2header.h \ + id3v2synchdata.h id3v2footer.h id3v2framefactory.h id3v2tag.h + +taglib_includedir = $(includedir)/taglib + +if link_zlib +zlib = -lz +endif + +libid3v2_la_LIBADD = ./frames/libframes.la $(zlib) + +EXTRA_DIST = $(libid3v2_la_SOURCES) $(taglib_include_HEADERS) id3v2.4.0-frames.txt id3v2.4.0-structure.txt diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/Makefile.in b/Libraries/TagLib/Files/taglib/mpeg/id3v2/Makefile.in new file mode 100644 index 000000000..ce469e13b --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/Makefile.in @@ -0,0 +1,686 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +SUBDIRS = frames +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/mpeg \ + -I$(top_srcdir)/taglib/mpeg/id3v1 \ + $(all_includes) + + +noinst_LTLIBRARIES = libid3v2.la + +libid3v2_la_SOURCES = \ + id3v2framefactory.cpp id3v2synchdata.cpp id3v2tag.cpp \ + id3v2header.cpp id3v2frame.cpp id3v2footer.cpp \ + id3v2extendedheader.cpp + + +taglib_include_HEADERS = \ + id3v2extendedheader.h id3v2frame.h id3v2header.h \ + id3v2synchdata.h id3v2footer.h id3v2framefactory.h id3v2tag.h + + +taglib_includedir = $(includedir)/taglib + +@link_zlib_TRUE@zlib = -lz + +libid3v2_la_LIBADD = ./frames/libframes.la $(zlib) + +EXTRA_DIST = $(libid3v2_la_SOURCES) $(taglib_include_HEADERS) id3v2.4.0-frames.txt id3v2.4.0-structure.txt +subdir = taglib/mpeg/id3v2 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libid3v2_la_LDFLAGS = +@link_zlib_TRUE@libid3v2_la_DEPENDENCIES = ./frames/libframes.la +@link_zlib_FALSE@libid3v2_la_DEPENDENCIES = ./frames/libframes.la +am_libid3v2_la_OBJECTS = id3v2framefactory.lo id3v2synchdata.lo \ + id3v2tag.lo id3v2header.lo id3v2frame.lo id3v2footer.lo \ + id3v2extendedheader.lo +#>- libid3v2_la_OBJECTS = $(am_libid3v2_la_OBJECTS) +#>+ 6 +libid3v2_la_final_OBJECTS = libid3v2_la.all_cpp.lo +libid3v2_la_nofinal_OBJECTS = id3v2framefactory.lo id3v2synchdata.lo \ + id3v2tag.lo id3v2header.lo id3v2frame.lo id3v2footer.lo \ + id3v2extendedheader.lo +@KDE_USE_FINAL_FALSE@libid3v2_la_OBJECTS = $(libid3v2_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libid3v2_la_OBJECTS = $(libid3v2_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/id3v2extendedheader.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/id3v2footer.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/id3v2frame.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/id3v2framefactory.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/id3v2header.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/id3v2synchdata.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/id3v2tag.Plo +#>+ 15 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libid3v2_la.all_cpp.P ./$(DEPDIR)/id3v2extendedheader.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2footer.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2frame.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2framefactory.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2header.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2synchdata.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2tag.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/id3v2extendedheader.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2footer.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2frame.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2framefactory.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2header.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2synchdata.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/id3v2tag.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libid3v2_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + + +RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ + ps-recursive install-info-recursive uninstall-info-recursive \ + all-recursive install-data-recursive install-exec-recursive \ + installdirs-recursive install-recursive uninstall-recursive \ + check-recursive installcheck-recursive +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +DIST_SUBDIRS = $(SUBDIRS) +SOURCES = $(libid3v2_la_SOURCES) + +#>- all: all-recursive +#>+ 1 +all: docs-am all-recursive + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/mpeg/id3v2/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/id3v2/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/id3v2/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libid3v2.la: $(libid3v2_la_OBJECTS) $(libid3v2_la_DEPENDENCIES) + $(CXXLINK) $(libid3v2_la_LDFLAGS) $(libid3v2_la_OBJECTS) $(libid3v2_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v2extendedheader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v2footer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v2frame.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v2framefactory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v2header.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v2synchdata.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id3v2tag.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + 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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: ctags-recursive $(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 +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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-recursive +#>+ 1 +clean: kde-rpo-clean clean-recursive + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-taglib_includeHEADERS + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-recursive distclean-tags distdir \ + dvi dvi-am dvi-recursive info info-am info-recursive install \ + install-am install-data install-data-am install-data-recursive \ + install-exec install-exec-am install-exec-recursive \ + install-info install-info-am install-info-recursive install-man \ + install-recursive install-strip install-taglib_includeHEADERS \ + installcheck installcheck-am installdirs installdirs-am \ + installdirs-recursive maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ + pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ + tags-recursive uninstall uninstall-am uninstall-info-am \ + uninstall-info-recursive uninstall-recursive \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/id3v2/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/id3v2/Makefile.in + + +#>+ 11 +libid3v2_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/id3v2framefactory.cpp $(srcdir)/id3v2synchdata.cpp $(srcdir)/id3v2tag.cpp $(srcdir)/id3v2header.cpp $(srcdir)/id3v2frame.cpp $(srcdir)/id3v2footer.cpp $(srcdir)/id3v2extendedheader.cpp + @echo 'creating libid3v2_la.all_cpp.cpp ...'; \ + rm -f libid3v2_la.all_cpp.files libid3v2_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libid3v2_la.all_cpp.final; \ + for file in id3v2framefactory.cpp id3v2synchdata.cpp id3v2tag.cpp id3v2header.cpp id3v2frame.cpp id3v2footer.cpp id3v2extendedheader.cpp ; do \ + echo "#include \"$$file\"" >> libid3v2_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libid3v2_la.all_cpp.final; \ + done; \ + cat libid3v2_la.all_cpp.final libid3v2_la.all_cpp.files > libid3v2_la.all_cpp.cpp; \ + rm -f libid3v2_la.all_cpp.final libid3v2_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libid3v2_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libid3v2_la_OBJECTS="$(libid3v2_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libid3v2_la_OBJECTS="$(libid3v2_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libid3v2_la_OBJECTS="$(libid3v2_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libid3v2_la_OBJECTS="$(libid3v2_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/Makefile.am b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/Makefile.am new file mode 100644 index 000000000..929485b3b --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/Makefile.am @@ -0,0 +1,27 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/mpeg/id3v2 \ + $(all_includes) + +noinst_LTLIBRARIES = libframes.la + +libframes_la_SOURCES = \ + attachedpictureframe.cpp \ + commentsframe.cpp \ + relativevolumeframe.cpp \ + textidentificationframe.cpp \ + uniquefileidentifierframe.cpp \ + unknownframe.cpp + +taglib_include_HEADERS = \ + attachedpictureframe.h \ + commentsframe.h \ + relativevolumeframe.h \ + textidentificationframe.h \ + uniquefileidentifierframe.h \ + unknownframe.h + +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libframes_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/Makefile.in b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/Makefile.in new file mode 100644 index 000000000..9395c4584 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/Makefile.in @@ -0,0 +1,583 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/mpeg/id3v2 \ + $(all_includes) + + +noinst_LTLIBRARIES = libframes.la + +libframes_la_SOURCES = \ + attachedpictureframe.cpp \ + commentsframe.cpp \ + relativevolumeframe.cpp \ + textidentificationframe.cpp \ + uniquefileidentifierframe.cpp \ + unknownframe.cpp + + +taglib_include_HEADERS = \ + attachedpictureframe.h \ + commentsframe.h \ + relativevolumeframe.h \ + textidentificationframe.h \ + uniquefileidentifierframe.h \ + unknownframe.h + + +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libframes_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/mpeg/id3v2/frames +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libframes_la_LDFLAGS = +libframes_la_LIBADD = +am_libframes_la_OBJECTS = attachedpictureframe.lo commentsframe.lo \ + relativevolumeframe.lo textidentificationframe.lo \ + uniquefileidentifierframe.lo unknownframe.lo +#>- libframes_la_OBJECTS = $(am_libframes_la_OBJECTS) +#>+ 6 +libframes_la_final_OBJECTS = libframes_la.all_cpp.lo +libframes_la_nofinal_OBJECTS = attachedpictureframe.lo commentsframe.lo \ + relativevolumeframe.lo textidentificationframe.lo \ + uniquefileidentifierframe.lo unknownframe.lo +@KDE_USE_FINAL_FALSE@libframes_la_OBJECTS = $(libframes_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libframes_la_OBJECTS = $(libframes_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/attachedpictureframe.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/commentsframe.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/relativevolumeframe.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/textidentificationframe.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/uniquefileidentifierframe.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/unknownframe.Plo +#>+ 13 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libframes_la.all_cpp.P ./$(DEPDIR)/attachedpictureframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/commentsframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/relativevolumeframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/textidentificationframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/uniquefileidentifierframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/unknownframe.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/attachedpictureframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/commentsframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/relativevolumeframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/textidentificationframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/uniquefileidentifierframe.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/unknownframe.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libframes_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(libframes_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/mpeg/id3v2/frames/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/id3v2/frames/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/id3v2/frames/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libframes.la: $(libframes_la_OBJECTS) $(libframes_la_DEPENDENCIES) + $(CXXLINK) $(libframes_la_LDFLAGS) $(libframes_la_OBJECTS) $(libframes_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attachedpictureframe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commentsframe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/relativevolumeframe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/textidentificationframe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uniquefileidentifierframe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unknownframe.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../../../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/mpeg/id3v2/frames/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/mpeg/id3v2/frames/Makefile.in + + +#>+ 11 +libframes_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/attachedpictureframe.cpp $(srcdir)/commentsframe.cpp $(srcdir)/relativevolumeframe.cpp $(srcdir)/textidentificationframe.cpp $(srcdir)/uniquefileidentifierframe.cpp $(srcdir)/unknownframe.cpp + @echo 'creating libframes_la.all_cpp.cpp ...'; \ + rm -f libframes_la.all_cpp.files libframes_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libframes_la.all_cpp.final; \ + for file in attachedpictureframe.cpp commentsframe.cpp relativevolumeframe.cpp textidentificationframe.cpp uniquefileidentifierframe.cpp unknownframe.cpp ; do \ + echo "#include \"$$file\"" >> libframes_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libframes_la.all_cpp.final; \ + done; \ + cat libframes_la.all_cpp.final libframes_la.all_cpp.files > libframes_la.all_cpp.cpp; \ + rm -f libframes_la.all_cpp.final libframes_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libframes_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libframes_la_OBJECTS="$(libframes_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libframes_la_OBJECTS="$(libframes_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libframes_la_OBJECTS="$(libframes_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libframes_la_OBJECTS="$(libframes_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp new file mode 100644 index 000000000..5700dfe64 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp @@ -0,0 +1,165 @@ +/*************************************************************************** + copyright : (C) 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include "attachedpictureframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class AttachedPictureFrame::AttachedPictureFramePrivate +{ +public: + AttachedPictureFramePrivate() : textEncoding(String::Latin1), + type(AttachedPictureFrame::Other) {} + + String::Type textEncoding; + String mimeType; + AttachedPictureFrame::Type type; + String description; + ByteVector data; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC") +{ + d = new AttachedPictureFramePrivate; +} + +AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data) +{ + setData(data); + d = new AttachedPictureFramePrivate; +} + +AttachedPictureFrame::~AttachedPictureFrame() +{ + delete d; +} + +String AttachedPictureFrame::toString() const +{ + String s = "[" + d->mimeType + "]"; + return d->description.isEmpty() ? s : d->description + " " + s; +} + +String::Type AttachedPictureFrame::textEncoding() const +{ + return d->textEncoding; +} + +void AttachedPictureFrame::setTextEncoding(String::Type t) +{ + d->textEncoding = t; +} + +String AttachedPictureFrame::mimeType() const +{ + return d->mimeType; +} + +void AttachedPictureFrame::setMimeType(const String &m) +{ + d->mimeType = m; +} + +AttachedPictureFrame::Type AttachedPictureFrame::type() const +{ + return d->type; +} + +void AttachedPictureFrame::setType(Type t) +{ + d->type = t; +} + +ByteVector AttachedPictureFrame::picture() const +{ + return d->data; +} + +void AttachedPictureFrame::setPicture(const ByteVector &p) +{ + d->data = p; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void AttachedPictureFrame::parseFields(const ByteVector &data) +{ + if(data.size() < 5) { + debug("A picture frame must contain at least 5 bytes."); + return; + } + + int pos = 0; + + d->textEncoding = String::Type(data[pos]); + pos += 1; + + int offset = data.find(textDelimiter(String::Latin1), pos); + if(offset < pos) + return; + d->mimeType = String(data.mid(pos, offset - pos), String::Latin1); + pos = offset + 1; + + d->type = Type(data[pos]); + pos += 1; + + offset = data.find(textDelimiter(d->textEncoding), pos); + if(offset < pos) + return; + d->description = String(data.mid(pos, offset - pos), d->textEncoding); + pos = offset + 1; + + d->data = data.mid(pos); +} + +ByteVector AttachedPictureFrame::renderFields() const +{ + ByteVector data; + + data.append(char(d->textEncoding)); + data.append(d->mimeType.data(String::Latin1)); + data.append(textDelimiter(String::Latin1)); + data.append(char(d->type)); + data.append(d->description.data(d->textEncoding)); + data.append(textDelimiter(d->textEncoding)); + data.append(d->data); + + return data; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h) +{ + d = new AttachedPictureFramePrivate; + parseFields(fieldData(data)); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/attachedpictureframe.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/attachedpictureframe.h new file mode 100644 index 000000000..896f00217 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/attachedpictureframe.h @@ -0,0 +1,195 @@ +/*************************************************************************** + copyright : (C) 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ATTACHEDPICTUREFRAME_H +#define TAGLIB_ATTACHEDPICTUREFRAME_H + +#include +#include + +namespace TagLib { + + namespace ID3v2 { + + //! An ID3v2 attached picture frame implementation + + /*! + * This is an implementation of ID3v2 attached pictures. Pictures may be + * included in tags, one per APIC frame (but there may be multiple APIC + * frames in a single tag). These pictures are usually in either JPEG or + * PNG format. + */ + + class AttachedPictureFrame : public Frame + { + friend class FrameFactory; + + public: + + /*! + * This describes the function or content of the picture. + */ + enum Type { + //! A type not enumerated below + Other = 0x00, + //! 32x32 PNG image that should be used as the file icon + FileIcon = 0x01, + //! File icon of a different size or format + OtherFileIcon = 0x02, + //! Front cover image of the album + FrontCover = 0x03, + //! Back cover image of the album + BackCover = 0x04, + //! Inside leaflet page of the album + LeafletPage = 0x05, + //! Image from the album itself + Media = 0x06, + //! Picture of the lead artist or soloist + LeadArtist = 0x07, + //! Picture of the artist or performer + Artist = 0x08, + //! Picture of the conductor + Conductor = 0x09, + //! Picture of the band or orchestra + Band = 0x0A, + //! Picture of the composer + Composer = 0x0B, + //! Picture of the lyricist or text writer + Lyricist = 0x0C, + //! Picture of the recording location or studio + RecordingLocation = 0x0D, + //! Picture of the artists during recording + DuringRecording = 0x0E, + //! Picture of the artists during performance + DuringPerformance = 0x0F, + //! Picture from a movie or video related to the track + MovieScreenCapture = 0x10, + //! Picture of a large, coloured fish + ColouredFish = 0x11, + //! Illustration related to the track + Illustration = 0x12, + //! Logo of the band or performer + BandLogo = 0x13, + //! Logo of the publisher (record company) + PublisherLogo = 0x14 + }; + + /*! + * Constructs an empty picture frame. The description, content and text + * encoding should be set manually. + */ + AttachedPictureFrame(); + + /*! + * Constructs an AttachedPicture frame based on \a data. + */ + explicit AttachedPictureFrame(const ByteVector &data); + + /*! + * Destroys the AttahcedPictureFrame instance. + */ + virtual ~AttachedPictureFrame(); + + /*! + * Returns a string containing the description and mime-type + */ + virtual String toString() const; + + /*! + * Returns the text encoding used for the description. + * + * \see setTextEncoding() + * \see description() + */ + String::Type textEncoding() const; + + /*! + * Set the text encoding used for the description. + * + * \see description() + */ + void setTextEncoding(String::Type t); + + /*! + * Returns the mime type of the image. This should in most cases be + * "image/png" or "image/jpeg". + */ + String mimeType() const; + + /*! + * Sets the mime type of the image. This should in most cases be + * "image/png" or "image/jpeg". + */ + void setMimeType(const String &m); + + /*! + * Returns the type of the image. + * + * \see Type + * \see setType() + */ + Type type() const; + + /*! + * Sets the type for the image. + * + * \see Type + * \see type() + */ + void setType(Type t); + + /*! + * Returns the image data as a ByteVector. + * + * \note ByteVector has a data() method that returns a const char * which + * should make it easy to export this data to external programs. + * + * \see setPicture() + * \see mimeType() + */ + ByteVector picture() const; + + /*! + * Sets the image data to \a p. \a p should be of the type specified in + * this frame's mime-type specification. + * + * \see picture() + * \see mimeType() + * \see setMimeType() + */ + void setPicture(const ByteVector &p); + + protected: + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + private: + AttachedPictureFrame(const ByteVector &data, Header *h); + AttachedPictureFrame(const AttachedPictureFrame &); + AttachedPictureFrame &operator=(const AttachedPictureFrame &); + + class AttachedPictureFramePrivate; + AttachedPictureFramePrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/commentsframe.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/commentsframe.cpp new file mode 100644 index 000000000..fcabbbc6c --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/commentsframe.cpp @@ -0,0 +1,152 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "commentsframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class CommentsFrame::CommentsFramePrivate +{ +public: + CommentsFramePrivate() : textEncoding(String::Latin1) {} + String::Type textEncoding; + ByteVector language; + String description; + String text; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM") +{ + d = new CommentsFramePrivate; + d->textEncoding = encoding; +} + +CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data) +{ + d = new CommentsFramePrivate; + setData(data); +} + +CommentsFrame::~CommentsFrame() +{ + delete d; +} + +String CommentsFrame::toString() const +{ + return d->text; +} + +ByteVector CommentsFrame::language() const +{ + return d->language; +} + +String CommentsFrame::description() const +{ + return d->description; +} + +String CommentsFrame::text() const +{ + return d->text; +} + +void CommentsFrame::setLanguage(const ByteVector &languageEncoding) +{ + d->language = languageEncoding.mid(0, 3); +} + +void CommentsFrame::setDescription(const String &s) +{ + d->description = s; +} + +void CommentsFrame::setText(const String &s) +{ + d->text = s; +} + + +String::Type CommentsFrame::textEncoding() const +{ + return d->textEncoding; +} + +void CommentsFrame::setTextEncoding(String::Type encoding) +{ + d->textEncoding = encoding; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void CommentsFrame::parseFields(const ByteVector &data) +{ + if(data.size() < 5) { + debug("A comment frame must contain at least 5 bytes."); + return; + } + + d->textEncoding = String::Type(data[0]); + d->language = data.mid(1, 3); + + int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2; + + ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign); + + if(l.size() == 2) { + d->description = String(l.front(), d->textEncoding); + d->text = String(l.back(), d->textEncoding); + } +} + +ByteVector CommentsFrame::renderFields() const +{ + ByteVector v; + + v.append(char(d->textEncoding)); + v.append(d->language.size() == 3 ? d->language : " "); + v.append(d->description.data(d->textEncoding)); + v.append(textDelimiter(d->textEncoding)); + v.append(d->text.data(d->textEncoding)); + + return v; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h) +{ + d = new CommentsFramePrivate(); + parseFields(fieldData(data)); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/commentsframe.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/commentsframe.h new file mode 100644 index 000000000..2c8b2c003 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/commentsframe.h @@ -0,0 +1,154 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_COMMENTSFRAME_H +#define TAGLIB_COMMENTSFRAME_H + +#include + +namespace TagLib { + + namespace ID3v2 { + + //! An implementation of ID3v2 comments + + /*! + * This implements the ID3v2 comment format. An ID3v2 comment concists of + * a language encoding, a description and a single text field. + */ + + class CommentsFrame : public Frame + { + friend class FrameFactory; + + public: + /*! + * Construct an empty comment frame that will use the text encoding + * \a encoding. + */ + explicit CommentsFrame(String::Type encoding = String::Latin1); + + /*! + * Construct a comment based on the data in \a data. + */ + explicit CommentsFrame(const ByteVector &data); + + /*! + * Destroys this CommentFrame instance. + */ + virtual ~CommentsFrame(); + + /*! + * Returns the text of this comment. + * + * \see text() + */ + virtual String toString() const; + + /*! + * Returns the language encoding as a 3 byte encoding as specified by + * ISO-639-2. + * + * \note Most taggers simply ignore this value. + * + * \see setLanguage() + */ + ByteVector language() const; + + /*! + * Returns the description of this comment. + * + * \note Most taggers simply ignore this value. + * + * \see setDescription() + */ + String description() const; + + /*! + * Returns the text of this comment. + * + * \see setText() + */ + String text() const; + + /*! + * Set the language using the 3 byte language code from + * ISO-639-2 to + * \a languageCode. + * + * \see language() + */ + void setLanguage(const ByteVector &languageCode); + + /*! + * Sets the description of the comment to \a s. + * + * \see decription() + */ + void setDescription(const String &s); + + /*! + * Sets the text portion of the comment to \a s. + * + * \see text() + */ + virtual void setText(const String &s); + + /*! + * Returns the text encoding that will be used in rendering this frame. + * This defaults to the type that was either specified in the constructor + * or read from the frame when parsed. + * + * \see setTextEncoding() + * \see render() + */ + String::Type textEncoding() const; + + /*! + * Sets the text encoding to be used when rendering this frame to + * \a encoding. + * + * \see textEncoding() + * \see render() + */ + void setTextEncoding(String::Type encoding); + + protected: + // Reimplementations. + + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + private: + /*! + * The constructor used by the FrameFactory. + */ + CommentsFrame(const ByteVector &data, Header *h); + CommentsFrame(const CommentsFrame &); + CommentsFrame &operator=(const CommentsFrame &); + + class CommentsFramePrivate; + CommentsFramePrivate *d; + }; + + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp new file mode 100644 index 000000000..171ba91dc --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp @@ -0,0 +1,137 @@ +/*************************************************************************** + copyright : (C) 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "relativevolumeframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class RelativeVolumeFrame::RelativeVolumeFramePrivate +{ +public: + RelativeVolumeFramePrivate() : channelType(Other), volumeAdjustment(0) {} + + String identification; + ChannelType channelType; + short volumeAdjustment; + PeakVolume peakVolume; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data) +{ + d = new RelativeVolumeFramePrivate; + setData(data); +} + +RelativeVolumeFrame::~RelativeVolumeFrame() +{ + delete d; +} + +String RelativeVolumeFrame::toString() const +{ + return d->identification; +} + +RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const +{ + return d->channelType; +} + +void RelativeVolumeFrame::setChannelType(ChannelType t) +{ + d->channelType = t; +} + +short RelativeVolumeFrame::volumeAdjustmentIndex() const +{ + return d->volumeAdjustment; +} + +void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index) +{ + d->volumeAdjustment = index; +} + +float RelativeVolumeFrame::volumeAdjustment() const +{ + return float(d->volumeAdjustment) / float(512); +} + +void RelativeVolumeFrame::setVolumeAdjustment(float adjustment) +{ + d->volumeAdjustment = short(adjustment / float(512)); +} + +RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const +{ + return d->peakVolume; +} + +void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak) +{ + d->peakVolume = peak; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void RelativeVolumeFrame::parseFields(const ByteVector &data) +{ + int pos = data.find(textDelimiter(String::Latin1)); + d->identification = String(data.mid(0, pos), String::Latin1); + + d->volumeAdjustment = data.mid(pos, 2).toShort(); + pos += 2; + + d->peakVolume.bitsRepresentingPeak = data[pos]; + pos += 1; + + d->peakVolume.peakVolume = data.mid(pos, d->peakVolume.bitsRepresentingPeak); +} + +ByteVector RelativeVolumeFrame::renderFields() const +{ + ByteVector data; + + data.append(d->identification.data(String::Latin1)); + data.append(textDelimiter(String::Latin1)); + data.append(ByteVector::fromShort(d->volumeAdjustment)); + data.append(char(d->peakVolume.bitsRepresentingPeak)); + data.append(d->peakVolume.peakVolume); + + return data; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h) +{ + d = new RelativeVolumeFramePrivate; + parseFields(fieldData(data)); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/relativevolumeframe.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/relativevolumeframe.h new file mode 100644 index 000000000..f2d9a9dc3 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/relativevolumeframe.h @@ -0,0 +1,207 @@ +/*************************************************************************** + copyright : (C) 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_RELATIVEVOLUMEFRAME_H +#define TAGLIB_RELATIVEVOLUMEFRAME_H + +#include + +namespace TagLib { + + namespace ID3v2 { + + //! An ID3v2 relative volume adjustment frame implementation + + /*! + * This is an implementation of ID3v2 relative volume adjustment. The + * presense of this frame makes it possible to specify an increase in volume + * for an audio file or specific audio tracks in that file. + * + * Multiple relative volume adjustment frames may be present in the tag + * each with a unique identification and describing volume adjustment for + * different channel types. + */ + + class RelativeVolumeFrame : public Frame + { + friend class FrameFactory; + + public: + + /*! + * This indicates the type of volume adjustment that should be applied. + */ + enum ChannelType { + //! A type not enumerated below + Other = 0x00, + //! The master volume for the track + MasterVolume = 0x01, + //! The front right audio channel + FrontRight = 0x02, + //! The front left audio channel + FrontLeft = 0x03, + //! The back right audio channel + BackRight = 0x04, + //! The back left audio channel + BackLeft = 0x05, + //! The front center audio channel + FrontCentre = 0x06, + //! The back center audio channel + BackCentre = 0x07, + //! The subwoofer audio channel + Subwoofer = 0x08 + }; + + //! Struct that stores the relevant values for ID3v2 peak volume + + /*! + * The peak volume is described as a series of bits that is padded to fill + * a block of bytes. These two values should always be updated in tandem. + */ + struct PeakVolume + { + /*! + * Constructs an empty peak volume description. + */ + PeakVolume() : bitsRepresentingPeak(0) {} + /*! + * The number of bits (in the range of 0 to 255) used to describe the + * peak volume. + */ + unsigned char bitsRepresentingPeak; + /*! + * The array of bits (represented as a series of bytes) used to describe + * the peak volume. + */ + ByteVector peakVolume; + }; + + /*! + * Constructs a RelativeVolumeFrame. The relevant data should be set + * manually. + */ + RelativeVolumeFrame(); + + /*! + * Constructs a RelativeVolumeFrame based on the contents of \a data. + */ + RelativeVolumeFrame(const ByteVector &data); + + /*! + * Destroys the RelativeVolumeFrame instance. + */ + virtual ~RelativeVolumeFrame(); + + /*! + * Returns the frame's identification. + * + * \see identification() + */ + virtual String toString() const; + + /*! + * Returns the channel type that this frame refers to. + * + * \see setChannelType() + */ + ChannelType channelType() const; + + /*! + * Sets the channel type that this frame refers to. + * + * \see channelType() + */ + void setChannelType(ChannelType t); + + /*! + * Returns the relative volume adjustment "index". As indicated by the + * ID3v2 standard this is a 16-bit signed integer that reflects the + * decibils of adjustment when divided by 512. + * + * \see setVolumeAdjustmentIndex() + * \see volumeAjustment() + */ + short volumeAdjustmentIndex() const; + + /*! + * Set the volume adjustment to \a index. As indicated by the ID3v2 + * standard this is a 16-bit signed integer that reflects the decibils of + * adjustment when divided by 512. + * + * \see volumeAdjustmentIndex() + * \see setVolumeAjustment() + */ + void setVolumeAdjustmentIndex(short index); + + /*! + * Returns the relative volume adjustment in decibels. + * + * \note Because this is actually stored internally as an "index" to this + * value the value returned by this method may not be identical to the + * value set using setVolumeAdjustment(). + * + * \see setVolumeAdjustment() + * \see volumeAdjustmentIndex() + */ + float volumeAdjustment() const; + + /*! + * Set the relative volume adjustment in decibels to \a adjustment. + * + * \note Because this is actually stored internally as an "index" to this + * value the value set by this method may not be identical to the one + * returned by volumeAdjustment(). + * + * \see setVolumeAdjustment() + * \see volumeAdjustmentIndex() + */ + void setVolumeAdjustment(float adjustment); + + /*! + * Returns the peak volume (represented as a length and a string of bits). + * + * \see setPeakVolume() + */ + PeakVolume peakVolume() const; + + /*! + * Sets the peak volume to \a peak. + * + * \see peakVolume() + */ + void setPeakVolume(const PeakVolume &peak); + + protected: + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + private: + RelativeVolumeFrame(const ByteVector &data, Header *h); + RelativeVolumeFrame(const RelativeVolumeFrame &); + RelativeVolumeFrame &operator=(const RelativeVolumeFrame &); + + class RelativeVolumeFramePrivate; + RelativeVolumeFramePrivate *d; + }; + + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/textidentificationframe.cpp new file mode 100644 index 000000000..ee2137875 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/textidentificationframe.cpp @@ -0,0 +1,245 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "textidentificationframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class TextIdentificationFrame::TextIdentificationFramePrivate +{ +public: + TextIdentificationFramePrivate() : textEncoding(String::Latin1) {} + String::Type textEncoding; + StringList fieldList; +}; + +//////////////////////////////////////////////////////////////////////////////// +// TextIdentificationFrame public members +//////////////////////////////////////////////////////////////////////////////// + +TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) : + Frame(type) +{ + d = new TextIdentificationFramePrivate; + d->textEncoding = encoding; +} + +TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) : + Frame(data) +{ + d = new TextIdentificationFramePrivate; + setData(data); +} + +TextIdentificationFrame::~TextIdentificationFrame() +{ + delete d; +} + +void TextIdentificationFrame::setText(const StringList &l) +{ + d->fieldList = l; +} + +void TextIdentificationFrame::setText(const String &s) +{ + d->fieldList = s; +} + +String TextIdentificationFrame::toString() const +{ + return d->fieldList.toString(); +} + +StringList TextIdentificationFrame::fieldList() const +{ + return d->fieldList; +} + +String::Type TextIdentificationFrame::textEncoding() const +{ + return d->textEncoding; +} + +void TextIdentificationFrame::setTextEncoding(String::Type encoding) +{ + d->textEncoding = encoding; +} + +//////////////////////////////////////////////////////////////////////////////// +// TextIdentificationFrame protected members +//////////////////////////////////////////////////////////////////////////////// + +void TextIdentificationFrame::parseFields(const ByteVector &data) +{ + // read the string data type (the first byte of the field data) + + d->textEncoding = String::Type(data[0]); + + // split the byte array into chunks based on the string type (two byte delimiter + // for unicode encodings) + + int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2; + + ByteVectorList l = ByteVectorList::split(data.mid(1), textDelimiter(d->textEncoding), byteAlign); + + d->fieldList.clear(); + + // append those split values to the list and make sure that the new string's + // type is the same specified for this frame + + for(ByteVectorList::Iterator it = l.begin(); it != l.end(); it++) { + String s(*it, d->textEncoding); + d->fieldList.append(s); + } +} + +ByteVector TextIdentificationFrame::renderFields() const +{ + ByteVector v; + + if(d->fieldList.size() > 0) { + + v.append(char(d->textEncoding)); + + for(StringList::Iterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) { + + // Since the field list is null delimited, if this is not the first + // element in the list, append the appropriate delimiter for this + // encoding. + + if(it != d->fieldList.begin()) + v.append(textDelimiter(d->textEncoding)); + + v.append((*it).data(d->textEncoding)); + } + } + + return v; +} + +//////////////////////////////////////////////////////////////////////////////// +// TextIdentificationFrame private members +//////////////////////////////////////////////////////////////////////////////// + +TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h) +{ + d = new TextIdentificationFramePrivate; + parseFields(fieldData(data)); +} + +//////////////////////////////////////////////////////////////////////////////// +// UserTextIdentificationFrame public members +//////////////////////////////////////////////////////////////////////////////// + +UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) : + TextIdentificationFrame("TXXX", encoding), + d(0) +{ + StringList l; + l.append(String::null); + l.append(String::null); + setText(l); +} + + +UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) : + TextIdentificationFrame(data) +{ + +} + +String UserTextIdentificationFrame::toString() const +{ + return "[" + description() + "] " + fieldList().toString(); +} + +String UserTextIdentificationFrame::description() const +{ + return !TextIdentificationFrame::fieldList().isEmpty() + ? TextIdentificationFrame::fieldList().front() + : String::null; +} + +StringList UserTextIdentificationFrame::fieldList() const +{ + StringList l = TextIdentificationFrame::fieldList(); + + if(!l.isEmpty()) { + StringList::Iterator it = l.begin(); + l.erase(it); + } + + return l; +} + +void UserTextIdentificationFrame::setText(const String &text) +{ + if(description().isEmpty()) + setDescription(String::null); + + TextIdentificationFrame::setText(StringList(description()).append(text)); +} + +void UserTextIdentificationFrame::setText(const StringList &fields) +{ + if(description().isEmpty()) + setDescription(String::null); + + TextIdentificationFrame::setText(StringList(description()).append(fields)); +} + +void UserTextIdentificationFrame::setDescription(const String &s) +{ + StringList l = fieldList(); + + if(l.isEmpty()) + l.append(s); + else + l[0] = s; + + TextIdentificationFrame::setText(l); +} + +UserTextIdentificationFrame *find(ID3v2::Tag *tag, const String &description) // static +{ + FrameList l = tag->frameList("TXXX"); + for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) { + UserTextIdentificationFrame *f = dynamic_cast(*it); + if(f && f->description() == description) + return f; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// UserTextIdentificationFrame private members +//////////////////////////////////////////////////////////////////////////////// + +UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) : + TextIdentificationFrame(data, h) +{ + +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/textidentificationframe.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/textidentificationframe.h new file mode 100644 index 000000000..00c13851e --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/textidentificationframe.h @@ -0,0 +1,241 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_TEXTIDENTIFICATIONFRAME_H +#define TAGLIB_TEXTIDENTIFICATIONFRAME_H + +#include + +#include + +namespace TagLib { + + namespace ID3v2 { + + class Tag; + + //! An ID3v2 text identification frame implementation + + /*! + * This is an implementation of the most common type of ID3v2 frame -- text + * identification frames. There are a number of variations on this. Those + * enumerated in the ID3v2.4 standard are: + * + *
    + *
  • TALB Album/Movie/Show title
  • + *
  • TBPM BPM (beats per minute)
  • + *
  • TCOM Composer
  • + *
  • TCON Content type
  • + *
  • TCOP Copyright message
  • + *
  • TDEN Encoding time
  • + *
  • TDLY Playlist delay
  • + *
  • TDOR Original release time
  • + *
  • TDRC Recording time
  • + *
  • TDRL Release time
  • + *
  • TDTG Tagging time
  • + *
  • TENC Encoded by
  • + *
  • TEXT Lyricist/Text writer
  • + *
  • TFLT File type
  • + *
  • TIPL Involved people list
  • + *
  • TIT1 Content group description
  • + *
  • TIT2 Title/songname/content description
  • + *
  • TIT3 Subtitle/Description refinement
  • + *
  • TKEY Initial key
  • + *
  • TLAN Language(s)
  • + *
  • TLEN Length
  • + *
  • TMCL Musician credits list
  • + *
  • TMED Media type
  • + *
  • TMOO Mood
  • + *
  • TOAL Original album/movie/show title
  • + *
  • TOFN Original filename
  • + *
  • TOLY Original lyricist(s)/text writer(s)
  • + *
  • TOPE Original artist(s)/performer(s)
  • + *
  • TOWN File owner/licensee
  • + *
  • TPE1 Lead performer(s)/Soloist(s)
  • + *
  • TPE2 Band/orchestra/accompaniment
  • + *
  • TPE3 Conductor/performer refinement
  • + *
  • TPE4 Interpreted, remixed, or otherwise modified by
  • + *
  • TPOS Part of a set
  • + *
  • TPRO Produced notice
  • + *
  • TPUB Publisher
  • + *
  • TRCK Track number/Position in set
  • + *
  • TRSN Internet radio station name
  • + *
  • TRSO Internet radio station owner
  • + *
  • TSOA Album sort order
  • + *
  • TSOP Performer sort order
  • + *
  • TSOT Title sort order
  • + *
  • TSRC ISRC (international standard recording code)
  • + *
  • TSSE Software/Hardware and settings used for encoding
  • + *
  • TSST Set subtitle
  • + *
+ * + * The ID3v2 Frames document gives a description of each of these formats + * and the expected order of strings in each. ID3v2::Header::frameID() can + * be used to determine the frame type. + */ + + class TextIdentificationFrame : public Frame + { + friend class FrameFactory; + + public: + /*! + * Construct an empty frame of type \a type. Uses \a encoding as the + * default text encoding. + * + * \note In this case you must specify the text encoding as it + * resolves the ambiguity between constructors. + */ + TextIdentificationFrame(const ByteVector &type, String::Type encoding); + + /*! + * This is a dual purpose constructor. \a data can either be binary data + * that should be parsed or (at a minimum) the frame ID. + */ + explicit TextIdentificationFrame(const ByteVector &data); + + /*! + * Destroys this TextIdentificationFrame instance. + */ + virtual ~TextIdentificationFrame(); + + /*! + * Text identification frames are a list of string fields. + * + * This function will accept either a StringList or a String (using the + * StringList constructor that accepts a single String). + * + * \note This will not change the text encoding of the frame even if the + * strings passed in are not of the same encoding. Please use + * setEncoding(s.type()) if you wish to change the encoding of the frame. + */ + void setText(const StringList &l); + + // Reimplementations. + + virtual void setText(const String &s); + virtual String toString() const; + + /*! + * Returns the text encoding that will be used in rendering this frame. + * This defaults to the type that was either specified in the constructor + * or read from the frame when parsed. + * + * \see setTextEncoding() + * \see render() + */ + String::Type textEncoding() const; + + /*! + * Sets the text encoding to be used when rendering this frame to + * \a encoding. + * + * \see textEncoding() + * \see render() + */ + void setTextEncoding(String::Type encoding); + + /*! + * Returns a list of the strings in this frame. + */ + StringList fieldList() const; + + protected: + // Reimplementations. + + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + /*! + * The constructor used by the FrameFactory. + */ + TextIdentificationFrame(const ByteVector &data, Header *h); + + private: + TextIdentificationFrame(const TextIdentificationFrame &); + TextIdentificationFrame &operator=(const TextIdentificationFrame &); + + class TextIdentificationFramePrivate; + TextIdentificationFramePrivate *d; + }; + + /*! + * This is a specialization of text identification frames that allows for + * user defined entries. Each entry has a description in addition to the + * normal list of fields that a text identification frame has. + * + * This description identifies the frame and must be unique. + */ + + //! An ID3v2 custom text identification frame implementationx + + class UserTextIdentificationFrame : public TextIdentificationFrame + { + friend class FrameFactory; + + public: + /*! + * Constructs an empty user defined text identification frame. For this to be + * a useful frame both a description and text must be set. + */ + explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1); + + /*! + * Creates a frame based on \a data. + */ + explicit UserTextIdentificationFrame(const ByteVector &data); + + virtual String toString() const; + + /*! + * Returns the description for this frame. + */ + String description() const; + + /*! + * Sets the description of the frame to \a s. \a s must be unique. You can + * check for the presense of another user defined text frame of the same type + * using find() and testing for null. + */ + void setDescription(const String &s); + + StringList fieldList() const; + void setText(const String &text); + void setText(const StringList &fields); + + /*! + * Searches for the user defined text frame with the description \a description + * in \a tag. This returns null if no matching frames were found. + */ + static UserTextIdentificationFrame *find(Tag *tag, const String &description); + + private: + UserTextIdentificationFrame(const ByteVector &data, Header *h); + UserTextIdentificationFrame(const TextIdentificationFrame &); + UserTextIdentificationFrame &operator=(const UserTextIdentificationFrame &); + + class UserTextIdentificationFramePrivate; + UserTextIdentificationFramePrivate *d; + }; + + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp new file mode 100644 index 000000000..0eee906c0 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + copyright : (C) 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include "uniquefileidentifierframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class UniqueFileIdentifierFrame::UniqueFileIdentifierFramePrivate +{ +public: + String owner; + ByteVector identifier; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public methods +//////////////////////////////////////////////////////////////////////////////// + +UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) : + ID3v2::Frame(data) +{ + d = new UniqueFileIdentifierFramePrivate; + setData(data); +} + +UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) : + ID3v2::Frame("UFID") +{ + d = new UniqueFileIdentifierFramePrivate; + d->owner = owner; + d->identifier = id; +} + +String UniqueFileIdentifierFrame::owner() const +{ + return d->owner; +} + +ByteVector UniqueFileIdentifierFrame::identifier() const +{ + return d->identifier; +} + +void UniqueFileIdentifierFrame::setOwner(const String &s) +{ + d->owner = s; +} + +void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v) +{ + d->identifier = v; +} + +String UniqueFileIdentifierFrame::toString() const +{ + return String::null; +} + +void UniqueFileIdentifierFrame::parseFields(const ByteVector &data) +{ + ByteVectorList fields = ByteVectorList::split(data, char(0)); + + if(fields.size() != 2) + return; + + d->owner = fields.front(); + d->identifier = fields.back(); +} + +ByteVector UniqueFileIdentifierFrame::renderFields() const +{ + ByteVector data; + + data.append(d->owner.data(String::Latin1)); + data.append(char(0)); + data.append(d->identifier); + + return data; +} + +UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) : + Frame(h) +{ + d = new UniqueFileIdentifierFramePrivate; + parseFields(fieldData(data)); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h new file mode 100644 index 000000000..a8bbfe8cb --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h @@ -0,0 +1,101 @@ +/*************************************************************************** + copyright : (C) 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_UNIQUEFILEIDENTIFIERFRAME +#define TAGLIB_UNIQUEFILEIDENTIFIERFRAME + +#include + +namespace TagLib { + + namespace ID3v2 { + + /*! + * This is an implementation of ID3v2 unique file identifier frames. This + * frame is used to identify the file in an arbitrary database identified + * by the owner field. + */ + + //! An implementation of ID3v2 unique identifier frames + + class UniqueFileIdentifierFrame : public ID3v2::Frame + { + friend class FrameFactory; + + public: + /*! + * Creates a uniqe file identifier frame based on \a data. + */ + UniqueFileIdentifierFrame(const ByteVector &data); + + /*! + * Creates a unique file identifier frame with the owner \a owner and + * the identification \a id. + */ + UniqueFileIdentifierFrame(const String &owner, const ByteVector &id); + + /*! + * Returns the owner for the frame; essentially this is the key for + * determining which identification scheme this key belongs to. This + * will usually either be an email address or URL for the person or tool + * used to create the unique identifier. + * + * \see setOwner() + */ + String owner() const; + + /*! + * Returns the unique identifier. Though sometimes this is a text string + * it also may be binary data and as much should be assumed when handling + * it. + */ + ByteVector identifier() const; + + /*! + * Sets the owner of the identification scheme to \a s. + * + * \see owner() + */ + void setOwner(const String &s); + + /*! + * Sets the unique file identifier to \a v. + * + * \see identifier() + */ + void setIdentifier(const ByteVector &v); + + virtual String toString() const; + + protected: + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + private: + UniqueFileIdentifierFrame(const ByteVector &data, Header *h); + + class UniqueFileIdentifierFramePrivate; + UniqueFileIdentifierFramePrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/unknownframe.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/unknownframe.cpp new file mode 100644 index 000000000..0f4ed2e82 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/unknownframe.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "unknownframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class UnknownFrame::UnknownFramePrivate +{ +public: + ByteVector fieldData; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +UnknownFrame::UnknownFrame(const ByteVector &data) : Frame(data) +{ + d = new UnknownFramePrivate; + setData(data); +} + +UnknownFrame::~UnknownFrame() +{ + delete d; +} + +String UnknownFrame::toString() const +{ + return String::null; +} + +ByteVector UnknownFrame::data() const +{ + return d->fieldData; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void UnknownFrame::parseFields(const ByteVector &data) +{ + d->fieldData = data; +} + +ByteVector UnknownFrame::renderFields() const +{ + return d->fieldData; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h) +{ + d = new UnknownFramePrivate; + parseFields(fieldData(data)); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/unknownframe.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/unknownframe.h new file mode 100644 index 000000000..21de8263c --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/frames/unknownframe.h @@ -0,0 +1,74 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_UNKNOWNFRAME_H +#define TAGLIB_UNKNOWNFRAME_H + +#include + +namespace TagLib { + + namespace ID3v2 { + + //! A frame type \e unknown to TagLib. + + /*! + * This class represents a frame type not known (or more often simply + * unimplemented) in TagLib. This is here provide a basic API for + * manipulating the binary data of unknown frames and to provide a means + * of rendering such \e unknown frames. + * + * Please note that a cleaner way of handling frame types that TagLib + * does not understand is to subclass ID3v2::Frame and ID3v2::FrameFactory + * to have your frame type supported through the standard ID3v2 mechanism. + */ + + class UnknownFrame : public Frame + { + friend class FrameFactory; + + public: + UnknownFrame(const ByteVector &data); + virtual ~UnknownFrame(); + + virtual String toString() const; + + /*! + * Returns the field data (everything but the header) for this frame. + */ + ByteVector data() const; + + protected: + virtual void parseFields(const ByteVector &data); + virtual ByteVector renderFields() const; + + private: + UnknownFrame(const ByteVector &data, Header *h); + UnknownFrame(const UnknownFrame &); + UnknownFrame &operator=(const UnknownFrame &); + + class UnknownFramePrivate; + UnknownFramePrivate *d; + }; + + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2.4.0-frames.txt b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2.4.0-frames.txt new file mode 100644 index 000000000..e176b9a71 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2.4.0-frames.txt @@ -0,0 +1,1734 @@ +$Id: id3v2.4.0-frames.txt 3 2005-06-02 18:16:43Z vspader $ + +Informal standard M. Nilsson +Document: id3v2.4.0-frames.txt 1st November 2000 + + + ID3 tag version 2.4.0 - Native Frames + +Status of this document + + This document is an informal standard and replaces the ID3v2.3.0 + standard [ID3v2]. A formal standard will use another revision number + even if the content is identical to document. The contents in this + document may change for clarifications but never for added or altered + functionallity. + + Distribution of this document is unlimited. + + +Abstract + + This document describes the frames natively supported by ID3v2.4.0, + which is a revised version of the ID3v2 informal standard [ID3v2.3.0] + version 2.3.0. The ID3v2 offers a flexible way of storing audio meta + information within audio file itself. The information may be + technical information, such as equalisation curves, as well as title, + performer, copyright etc. + + ID3v2.4.0 is meant to be as close as possible to ID3v2.3.0 in order + to allow for implementations to be revised as easily as possible. + + +1. Table of contents + + 2. Conventions in this document + 3. Default flags + 4. Declared ID3v2 frames + 4.1. Unique file identifier + 4.2. Text information frames + 4.2.1. Identification frames + 4.2.2. Involved persons frames + 4.2.3. Derived and subjective properties frames + 4.2.4. Rights and license frames + 4.2.5. Other text frames + 4.2.6. User defined text information frame + 4.3. URL link frames + 4.3.1. URL link frames - details + 4.3.2. User defined URL link frame + 4.4. Music CD Identifier + 4.5. Event timing codes + 4.6. MPEG location lookup table + 4.7. Synced tempo codes + 4.8. Unsynchronised lyrics/text transcription + 4.9. Synchronised lyrics/text + 4.10. Comments + 4.11. Relative volume adjustment (2) + 4.12. Equalisation (2) + 4.13. Reverb + 4.14. Attached picture + 4.15. General encapsulated object + 4.16. Play counter + 4.17. Popularimeter + 4.18. Recommended buffer size + 4.19. Audio encryption + 4.20. Linked information + 4.21. Position synchronisation frame + 4.22. Terms of use + 4.23. Ownership frame + 4.24. Commercial frame + 4.25. Encryption method registration + 4.26. Group identification registration + 4.27. Private frame + 4.28. Signature frame + 4.29. Seek frame + 4.30. Audio seek point index + 5. Copyright + 6. References + 7. Appendix + A. Appendix A - Genre List from ID3v1 + 8. Author's Address + + +2. Conventions in this document + + Text within "" is a text string exactly as it appears in a tag. + Numbers preceded with $ are hexadecimal and numbers preceded with % + are binary. $xx is used to indicate a byte with unknown content. %x + is used to indicate a bit with unknown content. The most significant + bit (MSB) of a byte is called 'bit 7' and the least significant bit + (LSB) is called 'bit 0'. + + A tag is the whole tag described the ID3v2 main structure document + [ID3v2-strct]. A frame is a block of information in the tag. The tag + consists of a header, frames and optional padding. A field is a piece + of information; one value, a string etc. A numeric string is a string + that consists of the characters "0123456789" only. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [KEYWORDS]. + + +3. Default flags + + The default settings for the frames described in this document can be + divided into the following classes. The flags may be set differently + if found more suitable by the software. + + 1. Discarded if tag is altered, discarded if file is altered. + + None. + + 2. Discarded if tag is altered, preserved if file is altered. + + None. + + 3. Preserved if tag is altered, discarded if file is altered. + + ASPI, AENC, ETCO, EQU2, MLLT, POSS, SEEK, SYLT, SYTC, RVA2, TENC, + TLEN + + 4. Preserved if tag is altered, preserved if file is altered. + + The rest of the frames. + + +4. Declared ID3v2 frames + + The following frames are declared in this draft. + + 4.19 AENC Audio encryption + 4.14 APIC Attached picture + 4.30 ASPI Audio seek point index + + 4.10 COMM Comments + 4.24 COMR Commercial frame + + 4.25 ENCR Encryption method registration + 4.12 EQU2 Equalisation (2) + 4.5 ETCO Event timing codes + + 4.15 GEOB General encapsulated object + 4.26 GRID Group identification registration + + 4.20 LINK Linked information + + 4.4 MCDI Music CD identifier + 4.6 MLLT MPEG location lookup table + + 4.23 OWNE Ownership frame + + 4.27 PRIV Private frame + 4.16 PCNT Play counter + 4.17 POPM Popularimeter + 4.21 POSS Position synchronisation frame + + 4.18 RBUF Recommended buffer size + 4.11 RVA2 Relative volume adjustment (2) + 4.13 RVRB Reverb + + 4.29 SEEK Seek frame + 4.28 SIGN Signature frame + 4.9 SYLT Synchronised lyric/text + 4.7 SYTC Synchronised tempo codes + + 4.2.1 TALB Album/Movie/Show title + 4.2.3 TBPM BPM (beats per minute) + 4.2.2 TCOM Composer + 4.2.3 TCON Content type + 4.2.4 TCOP Copyright message + 4.2.5 TDEN Encoding time + 4.2.5 TDLY Playlist delay + 4.2.5 TDOR Original release time + 4.2.5 TDRC Recording time + 4.2.5 TDRL Release time + 4.2.5 TDTG Tagging time + 4.2.2 TENC Encoded by + 4.2.2 TEXT Lyricist/Text writer + 4.2.3 TFLT File type + 4.2.2 TIPL Involved people list + 4.2.1 TIT1 Content group description + 4.2.1 TIT2 Title/songname/content description + 4.2.1 TIT3 Subtitle/Description refinement + 4.2.3 TKEY Initial key + 4.2.3 TLAN Language(s) + 4.2.3 TLEN Length + 4.2.2 TMCL Musician credits list + 4.2.3 TMED Media type + 4.2.3 TMOO Mood + 4.2.1 TOAL Original album/movie/show title + 4.2.5 TOFN Original filename + 4.2.2 TOLY Original lyricist(s)/text writer(s) + 4.2.2 TOPE Original artist(s)/performer(s) + 4.2.4 TOWN File owner/licensee + 4.2.2 TPE1 Lead performer(s)/Soloist(s) + 4.2.2 TPE2 Band/orchestra/accompaniment + 4.2.2 TPE3 Conductor/performer refinement + 4.2.2 TPE4 Interpreted, remixed, or otherwise modified by + 4.2.1 TPOS Part of a set + 4.2.4 TPRO Produced notice + 4.2.4 TPUB Publisher + 4.2.1 TRCK Track number/Position in set + 4.2.4 TRSN Internet radio station name + 4.2.4 TRSO Internet radio station owner + 4.2.5 TSOA Album sort order + 4.2.5 TSOP Performer sort order + 4.2.5 TSOT Title sort order + 4.2.1 TSRC ISRC (international standard recording code) + 4.2.5 TSSE Software/Hardware and settings used for encoding + 4.2.1 TSST Set subtitle + 4.2.2 TXXX User defined text information frame + + 4.1 UFID Unique file identifier + 4.22 USER Terms of use + 4.8 USLT Unsynchronised lyric/text transcription + + 4.3.1 WCOM Commercial information + 4.3.1 WCOP Copyright/Legal information + 4.3.1 WOAF Official audio file webpage + 4.3.1 WOAR Official artist/performer webpage + 4.3.1 WOAS Official audio source webpage + 4.3.1 WORS Official Internet radio station homepage + 4.3.1 WPAY Payment + 4.3.1 WPUB Publishers official webpage + 4.3.2 WXXX User defined URL link frame + + +4.1. Unique file identifier + + This frame's purpose is to be able to identify the audio file in a + database, that may provide more information relevant to the content. + Since standardisation of such a database is beyond this document, all + UFID frames begin with an 'owner identifier' field. It is a null- + terminated string with a URL [URL] containing an email address, or a + link to a location where an email address can be found, that belongs + to the organisation responsible for this specific database + implementation. Questions regarding the database should be sent to + the indicated email address. The URL should not be used for the + actual database queries. The string + "http://www.id3.org/dummy/ufid.html" should be used for tests. The + 'Owner identifier' must be non-empty (more than just a termination). + The 'Owner identifier' is then followed by the actual identifier, + which may be up to 64 bytes. There may be more than one "UFID" frame + in a tag, but only one with the same 'Owner identifier'. + +
+ Owner identifier $00 + Identifier + + +4.2. Text information frames + + The text information frames are often the most important frames, + containing information like artist, album and more. There may only be + one text information frame of its kind in an tag. All text + information frames supports multiple strings, stored as a null + separated list, where null is reperesented by the termination code + for the charater encoding. All text frame identifiers begin with "T". + Only text frame identifiers begin with "T", with the exception of the + "TXXX" frame. All the text information frames have the following + format: + +
+ Text encoding $xx + Information + + +4.2.1. Identification frames + + TIT1 + The 'Content group description' frame is used if the sound belongs to + a larger category of sounds/music. For example, classical music is + often sorted in different musical sections (e.g. "Piano Concerto", + "Weather - Hurricane"). + + TIT2 + The 'Title/Songname/Content description' frame is the actual name of + the piece (e.g. "Adagio", "Hurricane Donna"). + + TIT3 + The 'Subtitle/Description refinement' frame is used for information + directly related to the contents title (e.g. "Op. 16" or "Performed + live at Wembley"). + + TALB + The 'Album/Movie/Show title' frame is intended for the title of the + recording (or source of sound) from which the audio in the file is + taken. + + TOAL + The 'Original album/movie/show title' frame is intended for the title + of the original recording (or source of sound), if for example the + music in the file should be a cover of a previously released song. + + TRCK + The 'Track number/Position in set' frame is a numeric string + containing the order number of the audio-file on its original + recording. This MAY be extended with a "/" character and a numeric + string containing the total number of tracks/elements on the original + recording. E.g. "4/9". + + TPOS + The 'Part of a set' frame is a numeric string that describes which + part of a set the audio came from. This frame is used if the source + described in the "TALB" frame is divided into several mediums, e.g. a + double CD. The value MAY be extended with a "/" character and a + numeric string containing the total number of parts in the set. E.g. + "1/2". + + TSST + The 'Set subtitle' frame is intended for the subtitle of the part of + a set this track belongs to. + + TSRC + The 'ISRC' frame should contain the International Standard Recording + Code [ISRC] (12 characters). + + +4.2.2. Involved persons frames + + TPE1 + The 'Lead artist/Lead performer/Soloist/Performing group' is + used for the main artist. + + TPE2 + The 'Band/Orchestra/Accompaniment' frame is used for additional + information about the performers in the recording. + + TPE3 + The 'Conductor' frame is used for the name of the conductor. + + TPE4 + The 'Interpreted, remixed, or otherwise modified by' frame contains + more information about the people behind a remix and similar + interpretations of another existing piece. + + TOPE + The 'Original artist/performer' frame is intended for the performer + of the original recording, if for example the music in the file + should be a cover of a previously released song. + + TEXT + The 'Lyricist/Text writer' frame is intended for the writer of the + text or lyrics in the recording. + + TOLY + The 'Original lyricist/text writer' frame is intended for the + text writer of the original recording, if for example the music in + the file should be a cover of a previously released song. + + TCOM + The 'Composer' frame is intended for the name of the composer. + + TMCL + The 'Musician credits list' is intended as a mapping between + instruments and the musician that played it. Every odd field is an + instrument and every even is an artist or a comma delimited list of + artists. + + TIPL + The 'Involved people list' is very similar to the musician credits + list, but maps between functions, like producer, and names. + + TENC + The 'Encoded by' frame contains the name of the person or + organisation that encoded the audio file. This field may contain a + copyright message, if the audio file also is copyrighted by the + encoder. + + +4.2.3. Derived and subjective properties frames + + TBPM + The 'BPM' frame contains the number of beats per minute in the + main part of the audio. The BPM is an integer and represented as a + numerical string. + + TLEN + The 'Length' frame contains the length of the audio file in + milliseconds, represented as a numeric string. + + TKEY + The 'Initial key' frame contains the musical key in which the sound + starts. It is represented as a string with a maximum length of three + characters. The ground keys are represented with "A","B","C","D","E", + "F" and "G" and halfkeys represented with "b" and "#". Minor is + represented as "m", e.g. "Dbm" $00. Off key is represented with an + "o" only. + + TLAN + The 'Language' frame should contain the languages of the text or + lyrics spoken or sung in the audio. The language is represented with + three characters according to ISO-639-2 [ISO-639-2]. If more than one + language is used in the text their language codes should follow + according to the amount of their usage, e.g. "eng" $00 "sve" $00. + + TCON + The 'Content type', which ID3v1 was stored as a one byte numeric + value only, is now a string. You may use one or several of the ID3v1 + types as numerical strings, or, since the category list would be + impossible to maintain with accurate and up to date categories, + define your own. Example: "21" $00 "Eurodisco" $00 + + You may also use any of the following keywords: + + RX Remix + CR Cover + + TFLT + The 'File type' frame indicates which type of audio this tag defines. + The following types and refinements are defined: + + MIME MIME type follows + MPG MPEG Audio + /1 MPEG 1/2 layer I + /2 MPEG 1/2 layer II + /3 MPEG 1/2 layer III + /2.5 MPEG 2.5 + /AAC Advanced audio compression + VQF Transform-domain Weighted Interleave Vector Quantisation + PCM Pulse Code Modulated audio + + but other types may be used, but not for these types though. This is + used in a similar way to the predefined types in the "TMED" frame, + but without parentheses. If this frame is not present audio type is + assumed to be "MPG". + + TMED + The 'Media type' frame describes from which media the sound + originated. This may be a text string or a reference to the + predefined media types found in the list below. Example: + "VID/PAL/VHS" $00. + + DIG Other digital media + /A Analogue transfer from media + + ANA Other analogue media + /WAC Wax cylinder + /8CA 8-track tape cassette + + CD CD + /A Analogue transfer from media + /DD DDD + /AD ADD + /AA AAD + + LD Laserdisc + + TT Turntable records + /33 33.33 rpm + /45 45 rpm + /71 71.29 rpm + /76 76.59 rpm + /78 78.26 rpm + /80 80 rpm + + MD MiniDisc + /A Analogue transfer from media + + DAT DAT + /A Analogue transfer from media + /1 standard, 48 kHz/16 bits, linear + /2 mode 2, 32 kHz/16 bits, linear + /3 mode 3, 32 kHz/12 bits, non-linear, low speed + /4 mode 4, 32 kHz/12 bits, 4 channels + /5 mode 5, 44.1 kHz/16 bits, linear + /6 mode 6, 44.1 kHz/16 bits, 'wide track' play + + DCC DCC + /A Analogue transfer from media + + DVD DVD + /A Analogue transfer from media + + TV Television + /PAL PAL + /NTSC NTSC + /SECAM SECAM + + VID Video + /PAL PAL + /NTSC NTSC + /SECAM SECAM + /VHS VHS + /SVHS S-VHS + /BETA BETAMAX + + RAD Radio + /FM FM + /AM AM + /LW LW + /MW MW + + TEL Telephone + /I ISDN + + MC MC (normal cassette) + /4 4.75 cm/s (normal speed for a two sided cassette) + /9 9.5 cm/s + /I Type I cassette (ferric/normal) + /II Type II cassette (chrome) + /III Type III cassette (ferric chrome) + /IV Type IV cassette (metal) + + REE Reel + /9 9.5 cm/s + /19 19 cm/s + /38 38 cm/s + /76 76 cm/s + /I Type I cassette (ferric/normal) + /II Type II cassette (chrome) + /III Type III cassette (ferric chrome) + /IV Type IV cassette (metal) + + TMOO + The 'Mood' frame is intended to reflect the mood of the audio with a + few keywords, e.g. "Romantic" or "Sad". + + +4.2.4. Rights and license frames + + TCOP + The 'Copyright message' frame, in which the string must begin with a + year and a space character (making five characters), is intended for + the copyright holder of the original sound, not the audio file + itself. The absence of this frame means only that the copyright + information is unavailable or has been removed, and must not be + interpreted to mean that the audio is public domain. Every time this + field is displayed the field must be preceded with "Copyright " (C) " + ", where (C) is one character showing a C in a circle. + + TPRO + The 'Produced notice' frame, in which the string must begin with a + year and a space character (making five characters), is intended for + the production copyright holder of the original sound, not the audio + file itself. The absence of this frame means only that the production + copyright information is unavailable or has been removed, and must + not be interpreted to mean that the audio is public domain. Every + time this field is displayed the field must be preceded with + "Produced " (P) " ", where (P) is one character showing a P in a + circle. + + TPUB + The 'Publisher' frame simply contains the name of the label or + publisher. + + TOWN + The 'File owner/licensee' frame contains the name of the owner or + licensee of the file and it's contents. + + TRSN + The 'Internet radio station name' frame contains the name of the + internet radio station from which the audio is streamed. + + TRSO + The 'Internet radio station owner' frame contains the name of the + owner of the internet radio station from which the audio is + streamed. + +4.2.5. Other text frames + + TOFN + The 'Original filename' frame contains the preferred filename for the + file, since some media doesn't allow the desired length of the + filename. The filename is case sensitive and includes its suffix. + + TDLY + The 'Playlist delay' defines the numbers of milliseconds of silence + that should be inserted before this audio. The value zero indicates + that this is a part of a multifile audio track that should be played + continuously. + + TDEN + The 'Encoding time' frame contains a timestamp describing when the + audio was encoded. Timestamp format is described in the ID3v2 + structure document [ID3v2-strct]. + + TDOR + The 'Original release time' frame contains a timestamp describing + when the original recording of the audio was released. Timestamp + format is described in the ID3v2 structure document [ID3v2-strct]. + + TDRC + The 'Recording time' frame contains a timestamp describing when the + audio was recorded. Timestamp format is described in the ID3v2 + structure document [ID3v2-strct]. + + TDRL + The 'Release time' frame contains a timestamp describing when the + audio was first released. Timestamp format is described in the ID3v2 + structure document [ID3v2-strct]. + + TDTG + The 'Tagging time' frame contains a timestamp describing then the + audio was tagged. Timestamp format is described in the ID3v2 + structure document [ID3v2-strct]. + + TSSE + The 'Software/Hardware and settings used for encoding' frame + includes the used audio encoder and its settings when the file was + encoded. Hardware refers to hardware encoders, not the computer on + which a program was run. + + TSOA + The 'Album sort order' frame defines a string which should be used + instead of the album name (TALB) for sorting purposes. E.g. an album + named "A Soundtrack" might preferably be sorted as "Soundtrack". + + TSOP + The 'Performer sort order' frame defines a string which should be + used instead of the performer (TPE2) for sorting purposes. + + TSOT + The 'Title sort order' frame defines a string which should be used + instead of the title (TIT2) for sorting purposes. + + +4.2.6. User defined text information frame + + This frame is intended for one-string text information concerning the + audio file in a similar way to the other "T"-frames. The frame body + consists of a description of the string, represented as a terminated + string, followed by the actual string. There may be more than one + "TXXX" frame in each tag, but only one with the same description. + +
+ Text encoding $xx + Description $00 (00) + Value + + +4.3. URL link frames + + With these frames dynamic data such as webpages with touring + information, price information or plain ordinary news can be added to + the tag. There may only be one URL [URL] link frame of its kind in an + tag, except when stated otherwise in the frame description. If the + text string is followed by a string termination, all the following + information should be ignored and not be displayed. All URL link + frame identifiers begins with "W". Only URL link frame identifiers + begins with "W", except for "WXXX". All URL link frames have the + following format: + +
+ URL + + +4.3.1. URL link frames - details + + WCOM + The 'Commercial information' frame is a URL pointing at a webpage + with information such as where the album can be bought. There may be + more than one "WCOM" frame in a tag, but not with the same content. + + WCOP + The 'Copyright/Legal information' frame is a URL pointing at a + webpage where the terms of use and ownership of the file is + described. + + WOAF + The 'Official audio file webpage' frame is a URL pointing at a file + specific webpage. + + WOAR + The 'Official artist/performer webpage' frame is a URL pointing at + the artists official webpage. There may be more than one "WOAR" frame + in a tag if the audio contains more than one performer, but not with + the same content. + + WOAS + The 'Official audio source webpage' frame is a URL pointing at the + official webpage for the source of the audio file, e.g. a movie. + + WORS + The 'Official Internet radio station homepage' contains a URL + pointing at the homepage of the internet radio station. + + WPAY + The 'Payment' frame is a URL pointing at a webpage that will handle + the process of paying for this file. + + WPUB + The 'Publishers official webpage' frame is a URL pointing at the + official webpage for the publisher. + + +4.3.2. User defined URL link frame + + This frame is intended for URL [URL] links concerning the audio file + in a similar way to the other "W"-frames. The frame body consists + of a description of the string, represented as a terminated string, + followed by the actual URL. The URL is always encoded with ISO-8859-1 + [ISO-8859-1]. There may be more than one "WXXX" frame in each tag, + but only one with the same description. + +
+ Text encoding $xx + Description $00 (00) + URL + + +4.4. Music CD identifier + + This frame is intended for music that comes from a CD, so that the CD + can be identified in databases such as the CDDB [CDDB]. The frame + consists of a binary dump of the Table Of Contents, TOC, from the CD, + which is a header of 4 bytes and then 8 bytes/track on the CD plus 8 + bytes for the 'lead out', making a maximum of 804 bytes. The offset + to the beginning of every track on the CD should be described with a + four bytes absolute CD-frame address per track, and not with absolute + time. When this frame is used the presence of a valid "TRCK" frame is + REQUIRED, even if the CD's only got one track. It is recommended that + this frame is always added to tags originating from CDs. There may + only be one "MCDI" frame in each tag. + +
+ CD TOC + + +4.5. Event timing codes + + This frame allows synchronisation with key events in the audio. The + header is: + +
+ Time stamp format $xx + + Where time stamp format is: + + $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit + $02 Absolute time, 32 bit sized, using milliseconds as unit + + Absolute time means that every stamp contains the time from the + beginning of the file. + + Followed by a list of key events in the following format: + + Type of event $xx + Time stamp $xx (xx ...) + + The 'Time stamp' is set to zero if directly at the beginning of the + sound or after the previous event. All events MUST be sorted in + chronological order. The type of event is as follows: + + $00 padding (has no meaning) + $01 end of initial silence + $02 intro start + $03 main part start + $04 outro start + $05 outro end + $06 verse start + $07 refrain start + $08 interlude start + $09 theme start + $0A variation start + $0B key change + $0C time change + $0D momentary unwanted noise (Snap, Crackle & Pop) + $0E sustained noise + $0F sustained noise end + $10 intro end + $11 main part end + $12 verse end + $13 refrain end + $14 theme end + $15 profanity + $16 profanity end + + $17-$DF reserved for future use + + $E0-$EF not predefined synch 0-F + + $F0-$FC reserved for future use + + $FD audio end (start of silence) + $FE audio file ends + $FF one more byte of events follows (all the following bytes with + the value $FF have the same function) + + Terminating the start events such as "intro start" is OPTIONAL. The + 'Not predefined synch's ($E0-EF) are for user events. You might want + to synchronise your music to something, like setting off an explosion + on-stage, activating a screensaver etc. + + There may only be one "ETCO" frame in each tag. + + +4.6. MPEG location lookup table + + To increase performance and accuracy of jumps within a MPEG [MPEG] + audio file, frames with time codes in different locations in the file + might be useful. This ID3v2 frame includes references that the + software can use to calculate positions in the file. After the frame + header follows a descriptor of how much the 'frame counter' should be + increased for every reference. If this value is two then the first + reference points out the second frame, the 2nd reference the 4th + frame, the 3rd reference the 6th frame etc. In a similar way the + 'bytes between reference' and 'milliseconds between reference' points + out bytes and milliseconds respectively. + + Each reference consists of two parts; a certain number of bits, as + defined in 'bits for bytes deviation', that describes the difference + between what is said in 'bytes between reference' and the reality and + a certain number of bits, as defined in 'bits for milliseconds + deviation', that describes the difference between what is said in + 'milliseconds between reference' and the reality. The number of bits + in every reference, i.e. 'bits for bytes deviation'+'bits for + milliseconds deviation', must be a multiple of four. There may only + be one "MLLT" frame in each tag. + +
+ MPEG frames between reference $xx xx + Bytes between reference $xx xx xx + Milliseconds between reference $xx xx xx + Bits for bytes deviation $xx + Bits for milliseconds dev. $xx + + Then for every reference the following data is included; + + Deviation in bytes %xxx.... + Deviation in milliseconds %xxx.... + + +4.7. Synchronised tempo codes + + For a more accurate description of the tempo of a musical piece, this + frame might be used. After the header follows one byte describing + which time stamp format should be used. Then follows one or more + tempo codes. Each tempo code consists of one tempo part and one time + part. The tempo is in BPM described with one or two bytes. If the + first byte has the value $FF, one more byte follows, which is added + to the first giving a range from 2 - 510 BPM, since $00 and $01 is + reserved. $00 is used to describe a beat-free time period, which is + not the same as a music-free time period. $01 is used to indicate one + single beat-stroke followed by a beat-free period. + + The tempo descriptor is followed by a time stamp. Every time the + tempo in the music changes, a tempo descriptor may indicate this for + the player. All tempo descriptors MUST be sorted in chronological + order. The first beat-stroke in a time-period is at the same time as + the beat description occurs. There may only be one "SYTC" frame in + each tag. + +
+ Time stamp format $xx + Tempo data + + Where time stamp format is: + + $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit + $02 Absolute time, 32 bit sized, using milliseconds as unit + + Absolute time means that every stamp contains the time from the + beginning of the file. + + +4.8. Unsynchronised lyrics/text transcription + + This frame contains the lyrics of the song or a text transcription of + other vocal activities. The head includes an encoding descriptor and + a content descriptor. The body consists of the actual text. The + 'Content descriptor' is a terminated string. If no descriptor is + entered, 'Content descriptor' is $00 (00) only. Newline characters + are allowed in the text. There may be more than one 'Unsynchronised + lyrics/text transcription' frame in each tag, but only one with the + same language and content descriptor. + +
+ Text encoding $xx + Language $xx xx xx + Content descriptor $00 (00) + Lyrics/text + + +4.9. Synchronised lyrics/text + + This is another way of incorporating the words, said or sung lyrics, + in the audio file as text, this time, however, in sync with the + audio. It might also be used to describing events e.g. occurring on a + stage or on the screen in sync with the audio. The header includes a + content descriptor, represented with as terminated text string. If no + descriptor is entered, 'Content descriptor' is $00 (00) only. + +
+ Text encoding $xx + Language $xx xx xx + Time stamp format $xx + Content type $xx + Content descriptor $00 (00) + + Content type: $00 is other + $01 is lyrics + $02 is text transcription + $03 is movement/part name (e.g. "Adagio") + $04 is events (e.g. "Don Quijote enters the stage") + $05 is chord (e.g. "Bb F Fsus") + $06 is trivia/'pop up' information + $07 is URLs to webpages + $08 is URLs to images + + Time stamp format: + + $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit + $02 Absolute time, 32 bit sized, using milliseconds as unit + + Absolute time means that every stamp contains the time from the + beginning of the file. + + The text that follows the frame header differs from that of the + unsynchronised lyrics/text transcription in one major way. Each + syllable (or whatever size of text is considered to be convenient by + the encoder) is a null terminated string followed by a time stamp + denoting where in the sound file it belongs. Each sync thus has the + following structure: + + Terminated text to be synced (typically a syllable) + Sync identifier (terminator to above string) $00 (00) + Time stamp $xx (xx ...) + + The 'time stamp' is set to zero or the whole sync is omitted if + located directly at the beginning of the sound. All time stamps + should be sorted in chronological order. The sync can be considered + as a validator of the subsequent string. + + Newline characters are allowed in all "SYLT" frames and MUST be used + after every entry (name, event etc.) in a frame with the content type + $03 - $04. + + A few considerations regarding whitespace characters: Whitespace + separating words should mark the beginning of a new word, thus + occurring in front of the first syllable of a new word. This is also + valid for new line characters. A syllable followed by a comma should + not be broken apart with a sync (both the syllable and the comma + should be before the sync). + + An example: The "USLT" passage + + "Strangers in the night" $0A "Exchanging glances" + + would be "SYLT" encoded as: + + "Strang" $00 xx xx "ers" $00 xx xx " in" $00 xx xx " the" $00 xx xx + " night" $00 xx xx 0A "Ex" $00 xx xx "chang" $00 xx xx "ing" $00 xx + xx "glan" $00 xx xx "ces" $00 xx xx + + There may be more than one "SYLT" frame in each tag, but only one + with the same language and content descriptor. + + +4.10. Comments + + This frame is intended for any kind of full text information that + does not fit in any other frame. It consists of a frame header + followed by encoding, language and content descriptors and is ended + with the actual comment as a text string. Newline characters are + allowed in the comment text string. There may be more than one + comment frame in each tag, but only one with the same language and + content descriptor. + +
+ Text encoding $xx + Language $xx xx xx + Short content descrip. $00 (00) + The actual text + + +4.11. Relative volume adjustment (2) + + This is a more subjective frame than the previous ones. It allows the + user to say how much he wants to increase/decrease the volume on each + channel when the file is played. The purpose is to be able to align + all files to a reference volume, so that you don't have to change the + volume constantly. This frame may also be used to balance adjust the + audio. The volume adjustment is encoded as a fixed point decibel + value, 16 bit signed integer representing (adjustment*512), giving + +/- 64 dB with a precision of 0.001953125 dB. E.g. +2 dB is stored as + $04 00 and -2 dB is $FC 00. There may be more than one "RVA2" frame + in each tag, but only one with the same identification string. + +
+ Identification $00 + + The 'identification' string is used to identify the situation and/or + device where this adjustment should apply. The following is then + repeated for every channel + + Type of channel $xx + Volume adjustment $xx xx + Bits representing peak $xx + Peak volume $xx (xx ...) + + + Type of channel: $00 Other + $01 Master volume + $02 Front right + $03 Front left + $04 Back right + $05 Back left + $06 Front centre + $07 Back centre + $08 Subwoofer + + Bits representing peak can be any number between 0 and 255. 0 means + that there is no peak volume field. The peak volume field is always + padded to whole bytes, setting the most significant bits to zero. + + +4.12. Equalisation (2) + + This is another subjective, alignment frame. It allows the user to + predefine an equalisation curve within the audio file. There may be + more than one "EQU2" frame in each tag, but only one with the same + identification string. + +
+ Interpolation method $xx + Identification $00 + + The 'interpolation method' describes which method is preferred when + an interpolation between the adjustment point that follows. The + following methods are currently defined: + + $00 Band + No interpolation is made. A jump from one adjustment level to + another occurs in the middle between two adjustment points. + $01 Linear + Interpolation between adjustment points is linear. + + The 'identification' string is used to identify the situation and/or + device where this adjustment should apply. The following is then + repeated for every adjustment point + + Frequency $xx xx + Volume adjustment $xx xx + + The frequency is stored in units of 1/2 Hz, giving it a range from 0 + to 32767 Hz. + + The volume adjustment is encoded as a fixed point decibel value, 16 + bit signed integer representing (adjustment*512), giving +/- 64 dB + with a precision of 0.001953125 dB. E.g. +2 dB is stored as $04 00 + and -2 dB is $FC 00. + + Adjustment points should be ordered by frequency and one frequency + should only be described once in the frame. + + +4.13. Reverb + + Yet another subjective frame, with which you can adjust echoes of + different kinds. Reverb left/right is the delay between every bounce + in ms. Reverb bounces left/right is the number of bounces that should + be made. $FF equals an infinite number of bounces. Feedback is the + amount of volume that should be returned to the next echo bounce. $00 + is 0%, $FF is 100%. If this value were $7F, there would be 50% volume + reduction on the first bounce, 50% of that on the second and so on. + Left to left means the sound from the left bounce to be played in the + left speaker, while left to right means sound from the left bounce to + be played in the right speaker. + + 'Premix left to right' is the amount of left sound to be mixed in the + right before any reverb is applied, where $00 id 0% and $FF is 100%. + 'Premix right to left' does the same thing, but right to left. + Setting both premix to $FF would result in a mono output (if the + reverb is applied symmetric). There may only be one "RVRB" frame in + each tag. + +
+ Reverb left (ms) $xx xx + Reverb right (ms) $xx xx + Reverb bounces, left $xx + Reverb bounces, right $xx + Reverb feedback, left to left $xx + Reverb feedback, left to right $xx + Reverb feedback, right to right $xx + Reverb feedback, right to left $xx + Premix left to right $xx + Premix right to left $xx + + +4.14. Attached picture + + This frame contains a picture directly related to the audio file. + Image format is the MIME type and subtype [MIME] for the image. In + the event that the MIME media type name is omitted, "image/" will be + implied. The "image/png" [PNG] or "image/jpeg" [JFIF] picture format + should be used when interoperability is wanted. Description is a + short description of the picture, represented as a terminated + text string. There may be several pictures attached to one file, each + in their individual "APIC" frame, but only one with the same content + descriptor. There may only be one picture with the picture type + declared as picture type $01 and $02 respectively. There is the + possibility to put only a link to the image file by using the 'MIME + type' "-->" and having a complete URL [URL] instead of picture data. + The use of linked files should however be used sparingly since there + is the risk of separation of files. + +
+ Text encoding $xx + MIME type $00 + Picture type $xx + Description $00 (00) + Picture data + + + Picture type: $00 Other + $01 32x32 pixels 'file icon' (PNG only) + $02 Other file icon + $03 Cover (front) + $04 Cover (back) + $05 Leaflet page + $06 Media (e.g. label side of CD) + $07 Lead artist/lead performer/soloist + $08 Artist/performer + $09 Conductor + $0A Band/Orchestra + $0B Composer + $0C Lyricist/text writer + $0D Recording Location + $0E During recording + $0F During performance + $10 Movie/video screen capture + $11 A bright coloured fish + $12 Illustration + $13 Band/artist logotype + $14 Publisher/Studio logotype + + +4.15. General encapsulated object + + In this frame any type of file can be encapsulated. After the header, + 'Frame size' and 'Encoding' follows 'MIME type' [MIME] represented as + as a terminated string encoded with ISO 8859-1 [ISO-8859-1]. The + filename is case sensitive and is encoded as 'Encoding'. Then follows + a content description as terminated string, encoded as 'Encoding'. + The last thing in the frame is the actual object. The first two + strings may be omitted, leaving only their terminations. MIME type is + always an ISO-8859-1 text string. There may be more than one "GEOB" + frame in each tag, but only one with the same content descriptor. + +
+ Text encoding $xx + MIME type $00 + Filename $00 (00) + Content description $00 (00) + Encapsulated object + + +4.16. Play counter + + This is simply a counter of the number of times a file has been + played. The value is increased by one every time the file begins to + play. There may only be one "PCNT" frame in each tag. When the + counter reaches all one's, one byte is inserted in front of the + counter thus making the counter eight bits bigger. The counter must + be at least 32-bits long to begin with. + +
+ Counter $xx xx xx xx (xx ...) + + +4.17. Popularimeter + + The purpose of this frame is to specify how good an audio file is. + Many interesting applications could be found to this frame such as a + playlist that features better audio files more often than others or + it could be used to profile a person's taste and find other 'good' + files by comparing people's profiles. The frame contains the email + address to the user, one rating byte and a four byte play counter, + intended to be increased with one for every time the file is played. + The email is a terminated string. The rating is 1-255 where 1 is + worst and 255 is best. 0 is unknown. If no personal counter is wanted + it may be omitted. When the counter reaches all one's, one byte is + inserted in front of the counter thus making the counter eight bits + bigger in the same away as the play counter ("PCNT"). There may be + more than one "POPM" frame in each tag, but only one with the same + email address. + +
+ Email to user $00 + Rating $xx + Counter $xx xx xx xx (xx ...) + + +4.18. Recommended buffer size + + Sometimes the server from which an audio file is streamed is aware of + transmission or coding problems resulting in interruptions in the + audio stream. In these cases, the size of the buffer can be + recommended by the server using this frame. If the 'embedded info + flag' is true (1) then this indicates that an ID3 tag with the + maximum size described in 'Buffer size' may occur in the audio + stream. In such case the tag should reside between two MPEG [MPEG] + frames, if the audio is MPEG encoded. If the position of the next tag + is known, 'offset to next tag' may be used. The offset is calculated + from the end of tag in which this frame resides to the first byte of + the header in the next. This field may be omitted. Embedded tags are + generally not recommended since this could render unpredictable + behaviour from present software/hardware. + + For applications like streaming audio it might be an idea to embed + tags into the audio stream though. If the clients connects to + individual connections like HTTP and there is a possibility to begin + every transmission with a tag, then this tag should include a + 'recommended buffer size' frame. If the client is connected to a + arbitrary point in the stream, such as radio or multicast, then the + 'recommended buffer size' frame SHOULD be included in every tag. + + The 'Buffer size' should be kept to a minimum. There may only be one + "RBUF" frame in each tag. + +
+ Buffer size $xx xx xx + Embedded info flag %0000000x + Offset to next tag $xx xx xx xx + + +4.19. Audio encryption + + This frame indicates if the actual audio stream is encrypted, and by + whom. Since standardisation of such encryption scheme is beyond this + document, all "AENC" frames begin with a terminated string with a + URL containing an email address, or a link to a location where an + email address can be found, that belongs to the organisation + responsible for this specific encrypted audio file. Questions + regarding the encrypted audio should be sent to the email address + specified. If a $00 is found directly after the 'Frame size' and the + audio file indeed is encrypted, the whole file may be considered + useless. + + After the 'Owner identifier', a pointer to an unencrypted part of the + audio can be specified. The 'Preview start' and 'Preview length' is + described in frames. If no part is unencrypted, these fields should + be left zeroed. After the 'preview length' field follows optionally a + data block required for decryption of the audio. There may be more + than one "AENC" frames in a tag, but only one with the same 'Owner + identifier'. + +
+ Owner identifier $00 + Preview start $xx xx + Preview length $xx xx + Encryption info + + +4.20. Linked information + + To keep information duplication as low as possible this frame may be + used to link information from another ID3v2 tag that might reside in + another audio file or alone in a binary file. It is RECOMMENDED that + this method is only used when the files are stored on a CD-ROM or + other circumstances when the risk of file separation is low. The + frame contains a frame identifier, which is the frame that should be + linked into this tag, a URL [URL] field, where a reference to the + file where the frame is given, and additional ID data, if needed. + Data should be retrieved from the first tag found in the file to + which this link points. There may be more than one "LINK" frame in a + tag, but only one with the same contents. A linked frame is to be + considered as part of the tag and has the same restrictions as if it + was a physical part of the tag (i.e. only one "RVRB" frame allowed, + whether it's linked or not). + +
+ Frame identifier $xx xx xx xx + URL $00 + ID and additional data + + Frames that may be linked and need no additional data are "ASPI", + "ETCO", "EQU2", "MCID", "MLLT", "OWNE", "RVA2", "RVRB", "SYTC", the + text information frames and the URL link frames. + + The "AENC", "APIC", "GEOB" and "TXXX" frames may be linked with + the content descriptor as additional ID data. + + The "USER" frame may be linked with the language field as additional + ID data. + + The "PRIV" frame may be linked with the owner identifier as + additional ID data. + + The "COMM", "SYLT" and "USLT" frames may be linked with three bytes + of language descriptor directly followed by a content descriptor as + additional ID data. + + +4.21. Position synchronisation frame + + This frame delivers information to the listener of how far into the + audio stream he picked up; in effect, it states the time offset from + the first frame in the stream. The frame layout is: + + + Time stamp format $xx + Position $xx (xx ...) + + Where time stamp format is: + + $01 Absolute time, 32 bit sized, using MPEG frames as unit + $02 Absolute time, 32 bit sized, using milliseconds as unit + + and position is where in the audio the listener starts to receive, + i.e. the beginning of the next frame. If this frame is used in the + beginning of a file the value is always 0. There may only be one + "POSS" frame in each tag. + + +4.22. Terms of use frame + + This frame contains a brief description of the terms of use and + ownership of the file. More detailed information concerning the legal + terms might be available through the "WCOP" frame. Newlines are + allowed in the text. There may be more than one 'Terms of use' frame + in a tag, but only one with the same 'Language'. + +
+ Text encoding $xx + Language $xx xx xx + The actual text + + +4.23. Ownership frame + + The ownership frame might be used as a reminder of a made transaction + or, if signed, as proof. Note that the "USER" and "TOWN" frames are + good to use in conjunction with this one. The frame begins, after the + frame ID, size and encoding fields, with a 'price paid' field. The + first three characters of this field contains the currency used for + the transaction, encoded according to ISO 4217 [ISO-4217] alphabetic + currency code. Concatenated to this is the actual price paid, as a + numerical string using "." as the decimal separator. Next is an 8 + character date string (YYYYMMDD) followed by a string with the name + of the seller as the last field in the frame. There may only be one + "OWNE" frame in a tag. + +
+ Text encoding $xx + Price paid $00 + Date of purch. + Seller + + +4.24. Commercial frame + + This frame enables several competing offers in the same tag by + bundling all needed information. That makes this frame rather complex + but it's an easier solution than if one tries to achieve the same + result with several frames. The frame begins, after the frame ID, + size and encoding fields, with a price string field. A price is + constructed by one three character currency code, encoded according + to ISO 4217 [ISO-4217] alphabetic currency code, followed by a + numerical value where "." is used as decimal separator. In the price + string several prices may be concatenated, separated by a "/" + character, but there may only be one currency of each type. + + The price string is followed by an 8 character date string in the + format YYYYMMDD, describing for how long the price is valid. After + that is a contact URL, with which the user can contact the seller, + followed by a one byte 'received as' field. It describes how the + audio is delivered when bought according to the following list: + + $00 Other + $01 Standard CD album with other songs + $02 Compressed audio on CD + $03 File over the Internet + $04 Stream over the Internet + $05 As note sheets + $06 As note sheets in a book with other sheets + $07 Music on other media + $08 Non-musical merchandise + + Next follows a terminated string with the name of the seller followed + by a terminated string with a short description of the product. The + last thing is the ability to include a company logotype. The first of + them is the 'Picture MIME type' field containing information about + which picture format is used. In the event that the MIME media type + name is omitted, "image/" will be implied. Currently only "image/png" + and "image/jpeg" are allowed. This format string is followed by the + binary picture data. This two last fields may be omitted if no + picture is attached. There may be more than one 'commercial frame' in + a tag, but no two may be identical. + +
+ Text encoding $xx + Price string $00 + Valid until + Contact URL $00 + Received as $xx + Name of seller $00 (00) + Description $00 (00) + Picture MIME type $00 + Seller logo + + +4.25. Encryption method registration + + To identify with which method a frame has been encrypted the + encryption method must be registered in the tag with this frame. The + 'Owner identifier' is a null-terminated string with a URL [URL] + containing an email address, or a link to a location where an email + address can be found, that belongs to the organisation responsible + for this specific encryption method. Questions regarding the + encryption method should be sent to the indicated email address. The + 'Method symbol' contains a value that is associated with this method + throughout the whole tag, in the range $80-F0. All other values are + reserved. The 'Method symbol' may optionally be followed by + encryption specific data. There may be several "ENCR" frames in a tag + but only one containing the same symbol and only one containing the + same owner identifier. The method must be used somewhere in the tag. + See the description of the frame encryption flag in the ID3v2 + structure document [ID3v2-strct] for more information. + +
+ Owner identifier $00 + Method symbol $xx + Encryption data + + +4.26. Group identification registration + + This frame enables grouping of otherwise unrelated frames. This can + be used when some frames are to be signed. To identify which frames + belongs to a set of frames a group identifier must be registered in + the tag with this frame. The 'Owner identifier' is a null-terminated + string with a URL [URL] containing an email address, or a link to a + location where an email address can be found, that belongs to the + organisation responsible for this grouping. Questions regarding the + grouping should be sent to the indicated email address. The 'Group + symbol' contains a value that associates the frame with this group + throughout the whole tag, in the range $80-F0. All other values are + reserved. The 'Group symbol' may optionally be followed by some group + specific data, e.g. a digital signature. There may be several "GRID" + frames in a tag but only one containing the same symbol and only one + containing the same owner identifier. The group symbol must be used + somewhere in the tag. See the description of the frame grouping flag + in the ID3v2 structure document [ID3v2-strct] for more information. + +
+ Owner identifier $00 + Group symbol $xx + Group dependent data + + +4.27. Private frame + + This frame is used to contain information from a software producer + that its program uses and does not fit into the other frames. The + frame consists of an 'Owner identifier' string and the binary data. + The 'Owner identifier' is a null-terminated string with a URL [URL] + containing an email address, or a link to a location where an email + address can be found, that belongs to the organisation responsible + for the frame. Questions regarding the frame should be sent to the + indicated email address. The tag may contain more than one "PRIV" + frame but only with different contents. + +
+ Owner identifier $00 + The private data + + +4.28. Signature frame + + This frame enables a group of frames, grouped with the 'Group + identification registration', to be signed. Although signatures can + reside inside the registration frame, it might be desired to store + the signature elsewhere, e.g. in watermarks. There may be more than + one 'signature frame' in a tag, but no two may be identical. + +
+ Group symbol $xx + Signature + + +4.29. Seek frame + + This frame indicates where other tags in a file/stream can be found. + The 'minimum offset to next tag' is calculated from the end of this + tag to the beginning of the next. There may only be one 'seek frame' + in a tag. + +
+ Minimum offset to next tag $xx xx xx xx + + +4.30. Audio seek point index + + Audio files with variable bit rates are intrinsically difficult to + deal with in the case of seeking within the file. The ASPI frame + makes seeking easier by providing a list a seek points within the + audio file. The seek points are a fractional offset within the audio + data, providing a starting point from which to find an appropriate + point to start decoding. The presence of an ASPI frame requires the + existence of a TLEN frame, indicating the duration of the file in + milliseconds. There may only be one 'audio seek point index' frame in + a tag. + +
+ Indexed data start (S) $xx xx xx xx + Indexed data length (L) $xx xx xx xx + Number of index points (N) $xx xx + Bits per index point (b) $xx + + Then for every index point the following data is included; + + Fraction at index (Fi) $xx (xx) + + 'Indexed data start' is a byte offset from the beginning of the file. + 'Indexed data length' is the byte length of the audio data being + indexed. 'Number of index points' is the number of index points, as + the name implies. The recommended number is 100. 'Bits per index + point' is 8 or 16, depending on the chosen precision. 8 bits works + well for short files (less than 5 minutes of audio), while 16 bits is + advantageous for long files. 'Fraction at index' is the numerator of + the fraction representing a relative position in the data. The + denominator is 2 to the power of b. + + Here are the algorithms to be used in the calculation. The known data + must be the offset of the start of the indexed data (S), the offset + of the end of the indexed data (E), the number of index points (N), + the offset at index i (Oi). We calculate the fraction at index i + (Fi). + + Oi is the offset of the frame whose start is soonest after the point + for which the time offset is (i/N * duration). + + The frame data should be calculated as follows: + + Fi = Oi/L * 2^b (rounded down to the nearest integer) + + Offset calculation should be calculated as follows from data in the + frame: + + Oi = (Fi/2^b)*L (rounded up to the nearest integer) + + +5. Copyright + + Copyright (C) Martin Nilsson 2000. All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that a reference to this document is included on all + such copies and derivative works. However, this document itself may + not be modified in any way and reissued as the original document. + + The limited permissions granted above are perpetual and will not be + revoked. + + This document and the information contained herein is provided on an + "AS IS" basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +6. References + + [CDDB] Compact Disc Data Base + + + + [ID3v2.3.0] Martin Nilsson, "ID3v2 informal standard". + + + + [ID3v2-strct] Martin Nilsson, + "ID3 tag version 2.4.0 - Main Structure" + + + + [ISO-639-2] ISO/FDIS 639-2. + Codes for the representation of names of languages, Part 2: Alpha-3 + code. Technical committee / subcommittee: TC 37 / SC 2 + + [ISO-4217] ISO 4217:1995. + Codes for the representation of currencies and funds. + Technical committee / subcommittee: TC 68 + + [ISO-8859-1] ISO/IEC DIS 8859-1. + 8-bit single-byte coded graphic character sets, Part 1: Latin + alphabet No. 1. Technical committee / subcommittee: JTC 1 / SC 2 + + [ISRC] ISO 3901:1986 + International Standard Recording Code (ISRC). + Technical committee / subcommittee: TC 46 / SC 9 + + [JFIF] JPEG File Interchange Format, version 1.02 + + + + [KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate + Requirement Levels', RFC 2119, March 1997. + + + + [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message Bodies", + RFC 2045, November 1996. + + + + [MPEG] ISO/IEC 11172-3:1993. + Coding of moving pictures and associated audio for digital storage + media at up to about 1,5 Mbit/s, Part 3: Audio. + Technical committee / subcommittee: JTC 1 / SC 29 + and + ISO/IEC 13818-3:1995 + Generic coding of moving pictures and associated audio information, + Part 3: Audio. + Technical committee / subcommittee: JTC 1 / SC 29 + and + ISO/IEC DIS 13818-3 + Generic coding of moving pictures and associated audio information, + Part 3: Audio (Revision of ISO/IEC 13818-3:1995) + + + [PNG] Portable Network Graphics, version 1.0 + + + + [URL] T. Berners-Lee, L. Masinter & M. McCahill, "Uniform Resource + Locators (URL).", RFC 1738, December 1994. + + + + [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, "ZLIB + Compressed + Data Format Specification version 3.3", RFC 1950, May 1996. + + + + +7. Appendix + + +A. Appendix A - Genre List from ID3v1 + + The following genres is defined in ID3v1 + + 0.Blues + 1.Classic Rock + 2.Country + 3.Dance + 4.Disco + 5.Funk + 6.Grunge + 7.Hip-Hop + 8.Jazz + 9.Metal + 10.New Age + 11.Oldies + 12.Other + 13.Pop + 14.R&B + 15.Rap + 16.Reggae + 17.Rock + 18.Techno + 19.Industrial + 20.Alternative + 21.Ska + 22.Death Metal + 23.Pranks + 24.Soundtrack + 25.Euro-Techno + 26.Ambient + 27.Trip-Hop + 28.Vocal + 29.Jazz+Funk + 30.Fusion + 31.Trance + 32.Classical + 33.Instrumental + 34.Acid + 35.House + 36.Game + 37.Sound Clip + 38.Gospel + 39.Noise + 40.AlternRock + 41.Bass + 42.Soul + 43.Punk + 44.Space + 45.Meditative + 46.Instrumental Pop + 47.Instrumental Rock + 48.Ethnic + 49.Gothic + 50.Darkwave + 51.Techno-Industrial + 52.Electronic + 53.Pop-Folk + 54.Eurodance + 55.Dream + 56.Southern Rock + 57.Comedy + 58.Cult + 59.Gangsta + 60.Top 40 + 61.Christian Rap + 62.Pop/Funk + 63.Jungle + 64.Native American + 65.Cabaret + 66.New Wave + 67.Psychadelic + 68.Rave + 69.Showtunes + 70.Trailer + 71.Lo-Fi + 72.Tribal + 73.Acid Punk + 74.Acid Jazz + 75.Polka + 76.Retro + 77.Musical + 78.Rock & Roll + 79.Hard Rock + + +8. Author's Address + + Written by + + Martin Nilsson + Rydsvägen 246 C. 30 + SE-584 34 Linköping + Sweden + + Email: nilsson@id3.org diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2.4.0-structure.txt b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2.4.0-structure.txt new file mode 100644 index 000000000..5fa156a0a --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2.4.0-structure.txt @@ -0,0 +1,733 @@ + +Informal standard M. Nilsson +Document: id3v2.4.0-structure.txt 16 September 2001 + + + ID3 tag version 2.4.0 - Main Structure + +Status of this document + + This document is an informal standard and replaces the ID3v2.3.0 + standard [ID3v2]. A formal standard will use another revision number + even if the content is identical to document. The contents in this + document may change for clarifications but never for added or altered + functionallity. + + Distribution of this document is unlimited. + + +Abstract + + This document describes the main structure of ID3v2.4.0, which is a + revised version of the ID3v2 informal standard [ID3v2] version + 2.3.0. The ID3v2 offers a flexible way of storing audio meta + information within the audio file itself. The information may be + technical information, such as equalisation curves, as well as + title, performer, copyright etc. + + ID3v2.4.0 is meant to be as close as possible to ID3v2.3.0 in order + to allow for implementations to be revised as easily as possible. + + +1. Table of contents + + Status of this document + Abstract + 1. Table of contents + 2. Conventions in this document + 2. Standard overview + 3. ID3v2 overview + 3.1. ID3v2 header + 3.2. ID3v2 extended header + 3.3. Padding + 3.4. ID3v2 footer + 4. ID3v2 frames overview + 4.1. Frame header flags + 4.1.1. Frame status flags + 4.1.2. Frame format flags + 5. Tag location + 6. Unsynchronisation + 6.1. The unsynchronisation scheme + 6.2. Synchsafe integers + 7. Copyright + 8. References + 9. Author's Address + + +2. Conventions in this document + + Text within "" is a text string exactly as it appears in a tag. + Numbers preceded with $ are hexadecimal and numbers preceded with % + are binary. $xx is used to indicate a byte with unknown content. %x + is used to indicate a bit with unknown content. The most significant + bit (MSB) of a byte is called 'bit 7' and the least significant bit + (LSB) is called 'bit 0'. + + A tag is the whole tag described in this document. A frame is a block + of information in the tag. The tag consists of a header, frames and + optional padding. A field is a piece of information; one value, a + string etc. A numeric string is a string that consists of the + characters "0123456789" only. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [KEYWORDS]. + + +3. ID3v2 overview + + ID3v2 is a general tagging format for audio, which makes it possible + to store meta data about the audio inside the audio file itself. The + ID3 tag described in this document is mainly targeted at files + encoded with MPEG-1/2 layer I, MPEG-1/2 layer II, MPEG-1/2 layer III + and MPEG-2.5, but may work with other types of encoded audio or as a + stand alone format for audio meta data. + + ID3v2 is designed to be as flexible and expandable as possible to + meet new meta information needs that might arise. To achieve that + ID3v2 is constructed as a container for several information blocks, + called frames, whose format need not be known to the software that + encounters them. At the start of every frame is an unique and + predefined identifier, a size descriptor that allows software to skip + unknown frames and a flags field. The flags describes encoding + details and if the frame should remain in the tag, should it be + unknown to the software, if the file is altered. + + The bitorder in ID3v2 is most significant bit first (MSB). The + byteorder in multibyte numbers is most significant byte first (e.g. + $12345678 would be encoded $12 34 56 78), also known as big endian + and network byte order. + + Overall tag structure: + + +-----------------------------+ + | Header (10 bytes) | + +-----------------------------+ + | Extended Header | + | (variable length, OPTIONAL) | + +-----------------------------+ + | Frames (variable length) | + +-----------------------------+ + | Padding | + | (variable length, OPTIONAL) | + +-----------------------------+ + | Footer (10 bytes, OPTIONAL) | + +-----------------------------+ + + In general, padding and footer are mutually exclusive. See details in + sections 3.3, 3.4 and 5. + + +3.1. ID3v2 header + + The first part of the ID3v2 tag is the 10 byte tag header, laid out + as follows: + + ID3v2/file identifier "ID3" + ID3v2 version $04 00 + ID3v2 flags %abcd0000 + ID3v2 size 4 * %0xxxxxxx + + The first three bytes of the tag are always "ID3", to indicate that + this is an ID3v2 tag, directly followed by the two version bytes. The + first byte of ID3v2 version is its major version, while the second + byte is its revision number. In this case this is ID3v2.4.0. All + revisions are backwards compatible while major versions are not. If + software with ID3v2.4.0 and below support should encounter version + five or higher it should simply ignore the whole tag. Version or + revision will never be $FF. + + The version is followed by the ID3v2 flags field, of which currently + four flags are used. + + + a - Unsynchronisation + + Bit 7 in the 'ID3v2 flags' indicates whether or not + unsynchronisation is applied on all frames (see section 6.1 for + details); a set bit indicates usage. + + + b - Extended header + + The second bit (bit 6) indicates whether or not the header is + followed by an extended header. The extended header is described in + section 3.2. A set bit indicates the presence of an extended + header. + + + c - Experimental indicator + + The third bit (bit 5) is used as an 'experimental indicator'. This + flag SHALL always be set when the tag is in an experimental stage. + + + d - Footer present + + Bit 4 indicates that a footer (section 3.4) is present at the very + end of the tag. A set bit indicates the presence of a footer. + + + All the other flags MUST be cleared. If one of these undefined flags + are set, the tag might not be readable for a parser that does not + know the flags function. + + The ID3v2 tag size is stored as a 32 bit synchsafe integer (section + 6.2), making a total of 28 effective bits (representing up to 256MB). + + The ID3v2 tag size is the sum of the byte length of the extended + header, the padding and the frames after unsynchronisation. If a + footer is present this equals to ('total size' - 20) bytes, otherwise + ('total size' - 10) bytes. + + An ID3v2 tag can be detected with the following pattern: + $49 44 33 yy yy xx zz zz zz zz + Where yy is less than $FF, xx is the 'flags' byte and zz is less than + $80. + + +3.2. Extended header + + The extended header contains information that can provide further + insight in the structure of the tag, but is not vital to the correct + parsing of the tag information; hence the extended header is + optional. + + Extended header size 4 * %0xxxxxxx + Number of flag bytes $01 + Extended Flags $xx + + Where the 'Extended header size' is the size of the whole extended + header, stored as a 32 bit synchsafe integer. An extended header can + thus never have a size of fewer than six bytes. + + The extended flags field, with its size described by 'number of flag + bytes', is defined as: + + %0bcd0000 + + Each flag that is set in the extended header has data attached, which + comes in the order in which the flags are encountered (i.e. the data + for flag 'b' comes before the data for flag 'c'). Unset flags cannot + have any attached data. All unknown flags MUST be unset and their + corresponding data removed when a tag is modified. + + Every set flag's data starts with a length byte, which contains a + value between 0 and 127 ($00 - $7f), followed by data that has the + field length indicated by the length byte. If a flag has no attached + data, the value $00 is used as length byte. + + + b - Tag is an update + + If this flag is set, the present tag is an update of a tag found + earlier in the present file or stream. If frames defined as unique + are found in the present tag, they are to override any + corresponding ones found in the earlier tag. This flag has no + corresponding data. + + Flag data length $00 + + c - CRC data present + + If this flag is set, a CRC-32 [ISO-3309] data is included in the + extended header. The CRC is calculated on all the data between the + header and footer as indicated by the header's tag length field, + minus the extended header. Note that this includes the padding (if + there is any), but excludes the footer. The CRC-32 is stored as an + 35 bit synchsafe integer, leaving the upper four bits always + zeroed. + + Flag data length $05 + Total frame CRC 5 * %0xxxxxxx + + d - Tag restrictions + + For some applications it might be desired to restrict a tag in more + ways than imposed by the ID3v2 specification. Note that the + presence of these restrictions does not affect how the tag is + decoded, merely how it was restricted before encoding. If this flag + is set the tag is restricted as follows: + + Flag data length $01 + Restrictions %ppqrrstt + + p - Tag size restrictions + + 00 No more than 128 frames and 1 MB total tag size. + 01 No more than 64 frames and 128 KB total tag size. + 10 No more than 32 frames and 40 KB total tag size. + 11 No more than 32 frames and 4 KB total tag size. + + q - Text encoding restrictions + + 0 No restrictions + 1 Strings are only encoded with ISO-8859-1 [ISO-8859-1] or + UTF-8 [UTF-8]. + + r - Text fields size restrictions + + 00 No restrictions + 01 No string is longer than 1024 characters. + 10 No string is longer than 128 characters. + 11 No string is longer than 30 characters. + + Note that nothing is said about how many bytes is used to + represent those characters, since it is encoding dependent. If a + text frame consists of more than one string, the sum of the + strungs is restricted as stated. + + s - Image encoding restrictions + + 0 No restrictions + 1 Images are encoded only with PNG [PNG] or JPEG [JFIF]. + + t - Image size restrictions + + 00 No restrictions + 01 All images are 256x256 pixels or smaller. + 10 All images are 64x64 pixels or smaller. + 11 All images are exactly 64x64 pixels, unless required + otherwise. + + +3.3. Padding + + It is OPTIONAL to include padding after the final frame (at the end + of the ID3 tag), making the size of all the frames together smaller + than the size given in the tag header. A possible purpose of this + padding is to allow for adding a few additional frames or enlarge + existing frames within the tag without having to rewrite the entire + file. The value of the padding bytes must be $00. A tag MUST NOT have + any padding between the frames or between the tag header and the + frames. Furthermore it MUST NOT have any padding when a tag footer is + added to the tag. + + +3.4. ID3v2 footer + + To speed up the process of locating an ID3v2 tag when searching from + the end of a file, a footer can be added to the tag. It is REQUIRED + to add a footer to an appended tag, i.e. a tag located after all + audio data. The footer is a copy of the header, but with a different + identifier. + + ID3v2 identifier "3DI" + ID3v2 version $04 00 + ID3v2 flags %abcd0000 + ID3v2 size 4 * %0xxxxxxx + + +4. ID3v2 frame overview + + All ID3v2 frames consists of one frame header followed by one or more + fields containing the actual information. The header is always 10 + bytes and laid out as follows: + + Frame ID $xx xx xx xx (four characters) + Size 4 * %0xxxxxxx + Flags $xx xx + + The frame ID is made out of the characters capital A-Z and 0-9. + Identifiers beginning with "X", "Y" and "Z" are for experimental + frames and free for everyone to use, without the need to set the + experimental bit in the tag header. Bear in mind that someone else + might have used the same identifier as you. All other identifiers are + either used or reserved for future use. + + The frame ID is followed by a size descriptor containing the size of + the data in the final frame, after encryption, compression and + unsynchronisation. The size is excluding the frame header ('total + frame size' - 10 bytes) and stored as a 32 bit synchsafe integer. + + In the frame header the size descriptor is followed by two flag + bytes. These flags are described in section 4.1. + + There is no fixed order of the frames' appearance in the tag, + although it is desired that the frames are arranged in order of + significance concerning the recognition of the file. An example of + such order: UFID, TIT2, MCDI, TRCK ... + + A tag MUST contain at least one frame. A frame must be at least 1 + byte big, excluding the header. + + If nothing else is said, strings, including numeric strings and URLs + [URL], are represented as ISO-8859-1 [ISO-8859-1] characters in the + range $20 - $FF. Such strings are represented in frame descriptions + as , or if newlines are allowed. If + nothing else is said newline character is forbidden. In ISO-8859-1 a + newline is represented, when allowed, with $0A only. + + Frames that allow different types of text encoding contains a text + encoding description byte. Possible encodings: + + $00 ISO-8859-1 [ISO-8859-1]. Terminated with $00. + $01 UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All + strings in the same frame SHALL have the same byteorder. + Terminated with $00 00. + $02 UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM. + Terminated with $00 00. + $03 UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00. + + Strings dependent on encoding are represented in frame descriptions + as , or if newlines are allowed. Any empty strings of + type $01 which are NULL-terminated may have the Unicode BOM followed + by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00). + + The timestamp fields are based on a subset of ISO 8601. When being as + precise as possible the format of a time string is + yyyy-MM-ddTHH:mm:ss (year, "-", month, "-", day, "T", hour (out of + 24), ":", minutes, ":", seconds), but the precision may be reduced by + removing as many time indicators as wanted. Hence valid timestamps + are + yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm and + yyyy-MM-ddTHH:mm:ss. All time stamps are UTC. For durations, use + the slash character as described in 8601, and for multiple non- + contiguous dates, use multiple strings, if allowed by the frame + definition. + + The three byte language field, present in several frames, is used to + describe the language of the frame's content, according to ISO-639-2 + [ISO-639-2]. The language should be represented in lower case. If the + language is not known the string "XXX" should be used. + + All URLs [URL] MAY be relative, e.g. "picture.png", "../doc.txt". + + If a frame is longer than it should be, e.g. having more fields than + specified in this document, that indicates that additions to the + frame have been made in a later version of the ID3v2 standard. This + is reflected by the revision number in the header of the tag. + + +4.1. Frame header flags + + In the frame header the size descriptor is followed by two flag + bytes. All unused flags MUST be cleared. The first byte is for + 'status messages' and the second byte is a format description. If an + unknown flag is set in the first byte the frame MUST NOT be changed + without that bit cleared. If an unknown flag is set in the second + byte the frame is likely to not be readable. Some flags in the second + byte indicates that extra information is added to the header. These + fields of extra information is ordered as the flags that indicates + them. The flags field is defined as follows (l and o left out because + ther resemblence to one and zero): + + %0abc0000 %0h00kmnp + + Some frame format flags indicate that additional information fields + are added to the frame. This information is added after the frame + header and before the frame data in the same order as the flags that + indicates them. I.e. the four bytes of decompressed size will precede + the encryption method byte. These additions affects the 'frame size' + field, but are not subject to encryption or compression. + + The default status flags setting for a frame is, unless stated + otherwise, 'preserved if tag is altered' and 'preserved if file is + altered', i.e. %00000000. + + +4.1.1. Frame status flags + + a - Tag alter preservation + + This flag tells the tag parser what to do with this frame if it is + unknown and the tag is altered in any way. This applies to all + kinds of alterations, including adding more padding and reordering + the frames. + + 0 Frame should be preserved. + 1 Frame should be discarded. + + + b - File alter preservation + + This flag tells the tag parser what to do with this frame if it is + unknown and the file, excluding the tag, is altered. This does not + apply when the audio is completely replaced with other audio data. + + 0 Frame should be preserved. + 1 Frame should be discarded. + + + c - Read only + + This flag, if set, tells the software that the contents of this + frame are intended to be read only. Changing the contents might + break something, e.g. a signature. If the contents are changed, + without knowledge of why the frame was flagged read only and + without taking the proper means to compensate, e.g. recalculating + the signature, the bit MUST be cleared. + + +4.1.2. Frame format flags + + h - Grouping identity + + This flag indicates whether or not this frame belongs in a group + with other frames. If set, a group identifier byte is added to the + frame. Every frame with the same group identifier belongs to the + same group. + + 0 Frame does not contain group information + 1 Frame contains group information + + + k - Compression + + This flag indicates whether or not the frame is compressed. + A 'Data Length Indicator' byte MUST be included in the frame. + + 0 Frame is not compressed. + 1 Frame is compressed using zlib [zlib] deflate method. + If set, this requires the 'Data Length Indicator' bit + to be set as well. + + + m - Encryption + + This flag indicates whether or not the frame is encrypted. If set, + one byte indicating with which method it was encrypted will be + added to the frame. See description of the ENCR frame for more + information about encryption method registration. Encryption + should be done after compression. Whether or not setting this flag + requires the presence of a 'Data Length Indicator' depends on the + specific algorithm used. + + 0 Frame is not encrypted. + 1 Frame is encrypted. + + n - Unsynchronisation + + This flag indicates whether or not unsynchronisation was applied + to this frame. See section 6 for details on unsynchronisation. + If this flag is set all data from the end of this header to the + end of this frame has been unsynchronised. Although desirable, the + presence of a 'Data Length Indicator' is not made mandatory by + unsynchronisation. + + 0 Frame has not been unsynchronised. + 1 Frame has been unsyrchronised. + + p - Data length indicator + + This flag indicates that a data length indicator has been added to + the frame. The data length indicator is the value one would write + as the 'Frame length' if all of the frame format flags were + zeroed, represented as a 32 bit synchsafe integer. + + 0 There is no Data Length Indicator. + 1 A data length Indicator has been added to the frame. + + +5. Tag location + + The default location of an ID3v2 tag is prepended to the audio so + that players can benefit from the information when the data is + streamed. It is however possible to append the tag, or make a + prepend/append combination. When deciding upon where an unembedded + tag should be located, the following order of preference SHOULD be + considered. + + 1. Prepend the tag. + + 2. Prepend a tag with all vital information and add a second tag at + the end of the file, before tags from other tagging systems. The + first tag is required to have a SEEK frame. + + 3. Add a tag at the end of the file, before tags from other tagging + systems. + + In case 2 and 3 the tag can simply be appended if no other known tags + are present. The suggested method to find ID3v2 tags are: + + 1. Look for a prepended tag using the pattern found in section 3.1. + + 2. If a SEEK frame was found, use its values to guide further + searching. + + 3. Look for a tag footer, scanning from the back of the file. + + For every new tag that is found, the old tag should be discarded + unless the update flag in the extended header (section 3.2) is set. + + +6. Unsynchronisation + + The only purpose of unsynchronisation is to make the ID3v2 tag as + compatible as possible with existing software and hardware. There is + no use in 'unsynchronising' tags if the file is only to be processed + only by ID3v2 aware software and hardware. Unsynchronisation is only + useful with tags in MPEG 1/2 layer I, II and III, MPEG 2.5 and AAC + files. + + +6.1. The unsynchronisation scheme + + Whenever a false synchronisation is found within the tag, one zeroed + byte is inserted after the first false synchronisation byte. The + format of synchronisations that should be altered by ID3 encoders is + as follows: + + %11111111 111xxxxx + + and should be replaced with: + + %11111111 00000000 111xxxxx + + This has the side effect that all $FF 00 combinations have to be + altered, so they will not be affected by the decoding process. + Therefore all the $FF 00 combinations have to be replaced with the + $FF 00 00 combination during the unsynchronisation. + + To indicate usage of the unsynchronisation, the unsynchronisation + flag in the frame header should be set. This bit MUST be set if the + frame was altered by the unsynchronisation and SHOULD NOT be set if + unaltered. If all frames in the tag are unsynchronised the + unsynchronisation flag in the tag header SHOULD be set. It MUST NOT + be set if the tag has a frame which is not unsynchronised. + + Assume the first byte of the audio to be $FF. The special case when + the last byte of the last frame is $FF and no padding nor footer is + used will then introduce a false synchronisation. This can be solved + by adding a footer, adding padding or unsynchronising the frame and + add $00 to the end of the frame data, thus adding more byte to the + frame size than a normal unsynchronisation would. Although not + preferred, it is allowed to apply the last method on all frames + ending with $FF. + + It is preferred that the tag is either completely unsynchronised or + not unsynchronised at all. A completely unsynchronised tag has no + false synchonisations in it, as defined above, and does not end with + $FF. A completely non-unsynchronised tag contains no unsynchronised + frames, and thus the unsynchronisation flag in the header is cleared. + + Do bear in mind, that if compression or encryption is used, the + unsynchronisation scheme MUST be applied afterwards. When decoding an + unsynchronised frame, the unsynchronisation scheme MUST be reversed + first, encryption and decompression afterwards. + + +6.2. Synchsafe integers + + In some parts of the tag it is inconvenient to use the + unsychronisation scheme because the size of unsynchronised data is + not known in advance, which is particularly problematic with size + descriptors. The solution in ID3v2 is to use synchsafe integers, in + which there can never be any false synchs. Synchsafe integers are + integers that keep its highest bit (bit 7) zeroed, making seven bits + out of eight available. Thus a 32 bit synchsafe integer can store 28 + bits of information. + + Example: + + 255 (%11111111) encoded as a 16 bit synchsafe integer is 383 + (%00000001 01111111). + + +7. Copyright + + Copyright (C) Martin Nilsson 2000. All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that a reference to this document is included on all + such copies and derivative works. However, this document itself may + not be modified in any way and reissued as the original document. + + The limited permissions granted above are perpetual and will not be + revoked. + + This document and the information contained herein is provided on an + 'AS IS' basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +8. References + + [ID3v2] Martin Nilsson, 'ID3v2 informal standard'. + + + + [ISO-639-2] ISO/FDIS 639-2. + 'Codes for the representation of names of languages, Part 2: Alpha-3 + code.' Technical committee / subcommittee: TC 37 / SC 2 + + [ISO-3309] ISO 3309 + 'Information Processing Systems--Data Communication High-Level Data + Link Control Procedure--Frame Structure', IS 3309, October 1984, 3rd + Edition. + + [ISO-8859-1] ISO/IEC DIS 8859-1. + '8-bit single-byte coded graphic character sets, Part 1: Latin + alphabet No. 1.' Technical committee / subcommittee: JTC 1 / SC 2 + + [JFIF] 'JPEG File Interchange Format, version 1.02' + + + + [KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate + Requirement Levels', RFC 2119, March 1997. + + + + [MPEG] ISO/IEC 11172-3:1993. + 'Coding of moving pictures and associated audio for digital storage + media at up to about 1,5 Mbit/s, Part 3: Audio.' + Technical committee / subcommittee: JTC 1 / SC 29 + and + ISO/IEC 13818-3:1995 + 'Generic coding of moving pictures and associated audio information, + Part 3: Audio.' + Technical committee / subcommittee: JTC 1 / SC 29 + and + ISO/IEC DIS 13818-3 + 'Generic coding of moving pictures and associated audio information, + Part 3: Audio (Revision of ISO/IEC 13818-3:1995)' + + [PNG] 'Portable Network Graphics, version 1.0' + + + + [UNICODE] The Unicode Consortium, + 'The Unicode Standard Version 3.0', ISBN 0-201-61633-5. + + + + [URL] T. Berners-Lee, L. Masinter & M. McCahill, 'Uniform Resource + Locators (URL)', RFC 1738, December 1994. + + + + [UTF-8] F. Yergeau, 'UTF-8, a transformation format of ISO 10646', + RFC 2279, January 1998. + + + + [UTF-16] F. Yergeau, 'UTF-16, an encoding of ISO 10646', RFC 2781, + February 2000. + + + + [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, 'ZLIB + Compressed Data Format Specification version 3.3', RFC 1950, + May 1996. + + + + +9. Author's Address + + Written by + + Martin Nilsson + Rydsvägen 246 C. 30 + SE-584 34 Linköping + Sweden + + Email: nilsson@id3.org + diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2extendedheader.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2extendedheader.cpp new file mode 100644 index 000000000..ed6bfe3dc --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2extendedheader.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "id3v2extendedheader.h" +#include "id3v2synchdata.h" + +using namespace TagLib; +using namespace ID3v2; + +class ExtendedHeader::ExtendedHeaderPrivate +{ +public: + ExtendedHeaderPrivate() : size(0) {} + + uint size; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public methods +//////////////////////////////////////////////////////////////////////////////// + +ExtendedHeader::ExtendedHeader() +{ + d = new ExtendedHeaderPrivate(); +} + +ExtendedHeader::~ExtendedHeader() +{ + delete d; +} + +TagLib::uint ExtendedHeader::size() const +{ + return d->size; +} + +void ExtendedHeader::setData(const ByteVector &data) +{ + parse(data); +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void ExtendedHeader::parse(const ByteVector &data) +{ + d->size = SynchData::toUInt(data.mid(0, 4)); // (structure 3.2 "Extended header size") +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2extendedheader.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2extendedheader.h new file mode 100644 index 000000000..8ca0dff94 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2extendedheader.h @@ -0,0 +1,88 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V2EXTENDEDHEADER_H +#define TAGLIB_ID3V2EXTENDEDHEADER_H + +#include +#include + +namespace TagLib { + + namespace ID3v2 { + + //! ID3v2 extended header implementation + + /*! + * This class implements ID3v2 extended headers. It attempts to follow, + * both semantically and programatically, the structure specified in + * the ID3v2 standard. The API is based on the properties of ID3v2 extended + * headers specified there. If any of the terms used in this documentation + * are unclear please check the specification in the linked section. + * (Structure, 3.2) + */ + + class ExtendedHeader + { + public: + /*! + * Constructs an empty ID3v2 extended header. + */ + ExtendedHeader(); + + /*! + * Destroys the extended header. + */ + virtual ~ExtendedHeader(); + + /*! + * Returns the size of the extended header. This is variable for the + * extended header. + */ + uint size() const; + + /*! + * Sets the data that will be used as the extended header. Since the + * length is not known before the extended header has been parsed, this + * should just be a pointer to the first byte of the extended header. It + * will determine the length internally and make that available through + * size(). + */ + void setData(const ByteVector &data); + + protected: + /*! + * Called by setData() to parse the extended header data. It makes this + * information available through the public API. + */ + void parse(const ByteVector &data); + + private: + ExtendedHeader(const ExtendedHeader &); + ExtendedHeader &operator=(const ExtendedHeader &); + + class ExtendedHeaderPrivate; + ExtendedHeaderPrivate *d; + }; + + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2footer.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2footer.cpp new file mode 100644 index 000000000..073f059c9 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2footer.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "id3v2footer.h" +#include "id3v2header.h" + +using namespace TagLib; +using namespace ID3v2; + +class Footer::FooterPrivate +{ +public: + static const uint size = 10; +}; + +Footer::Footer() +{ + +} + +Footer::~Footer() +{ + +} + +const unsigned int Footer::size() +{ + return FooterPrivate::size; +} + +ByteVector Footer::render(const Header *header) const +{ + ByteVector headerData = header->render(); + headerData[0] = '3'; + headerData[1] = 'D'; + headerData[2] = 'I'; + return headerData; +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2footer.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2footer.h new file mode 100644 index 000000000..7a925f32a --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2footer.h @@ -0,0 +1,77 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V2FOOTER_H +#define TAGLIB_ID3V2FOOTER_H + +#include + +namespace TagLib { + + namespace ID3v2 { + + class Header; + + //! ID3v2 footer implementation + + /*! + * Per the ID3v2 specification, the tag's footer is just a copy of the + * information in the header. As such there is no API for reading the + * data from the header, it can just as easily be done from the header. + * + * In fact, at this point, TagLib does not even parse the footer since + * it is not useful internally. However, if the flag to include a footer + * has been set in the ID3v2::Tag, TagLib will render a footer. + */ + + class Footer + { + public: + /*! + * Constructs an empty ID3v2 footer. + */ + Footer(); + /*! + * Destroys the footer. + */ + virtual ~Footer(); + + /*! + * Returns the size of the footer. Presently this is always 10 bytes. + */ + static const unsigned int size(); + + /*! + * Renders the footer based on the data in \a header. + */ + ByteVector render(const Header *header) const; + + private: + Footer(const Footer &); + Footer &operator=(const Footer &); + + class FooterPrivate; + FooterPrivate *d; + }; + + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2frame.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2frame.cpp new file mode 100644 index 000000000..0675483ce --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2frame.cpp @@ -0,0 +1,467 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include + +#if HAVE_ZLIB +#include +#endif + +#include + +#include "id3v2frame.h" +#include "id3v2synchdata.h" + +using namespace TagLib; +using namespace ID3v2; + +class Frame::FramePrivate +{ +public: + FramePrivate() : + header(0) + {} + + ~FramePrivate() + { + delete header; + } + + Frame::Header *header; +}; + +//////////////////////////////////////////////////////////////////////////////// +// static methods +//////////////////////////////////////////////////////////////////////////////// + +TagLib::uint Frame::headerSize() +{ + return Header::size(); +} + +TagLib::uint Frame::headerSize(uint version) +{ + return Header::size(version); +} + +ByteVector Frame::textDelimiter(String::Type t) +{ + ByteVector d = char(0); + if(t == String::UTF16 || t == String::UTF16BE) + d.append(char(0)); + return d; +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Frame::~Frame() +{ + delete d; +} + +ByteVector Frame::frameID() const +{ + if(d->header) + return d->header->frameID(); + else + return ByteVector::null; +} + +TagLib::uint Frame::size() const +{ + if(d->header) + return d->header->frameSize(); + else + return 0; +} + +void Frame::setData(const ByteVector &data) +{ + parse(data); +} + +void Frame::setText(const String &) +{ + +} + +ByteVector Frame::render() const +{ + ByteVector fieldData = renderFields(); + d->header->setFrameSize(fieldData.size()); + ByteVector headerData = d->header->render(); + + return headerData + fieldData; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +Frame::Frame(const ByteVector &data) +{ + d = new FramePrivate; + d->header = new Header(data); +} + +Frame::Frame(Header *h) +{ + d = new FramePrivate; + d->header = h; +} + +Frame::Header *Frame::header() const +{ + return d->header; +} + +void Frame::setHeader(Header *h, bool deleteCurrent) +{ + if(deleteCurrent) + delete d->header; + + d->header = h; +} + +void Frame::parse(const ByteVector &data) +{ + if(d->header) + d->header->setData(data); + else + d->header = new Header(data); + + parseFields(fieldData(data)); +} + +ByteVector Frame::fieldData(const ByteVector &frameData) const +{ + uint headerSize = Header::size(d->header->version()); + + uint frameDataOffset = headerSize; + uint frameDataLength = size(); + + if(d->header->compression() || d->header->dataLengthIndicator()) { + frameDataLength = frameData.mid(headerSize, 4).toUInt(); + frameDataOffset += 4; + } + +#if HAVE_ZLIB + if(d->header->compression()) { + ByteVector data(frameDataLength); + uLongf uLongTmp = frameDataLength; + ::uncompress((Bytef *) data.data(), + (uLongf *) &uLongTmp, + (Bytef *) frameData.data() + frameDataOffset, + size()); + return data; + } + else +#endif + return frameData.mid(frameDataOffset, frameDataLength); +} + +//////////////////////////////////////////////////////////////////////////////// +// Frame::Header class +//////////////////////////////////////////////////////////////////////////////// + +class Frame::Header::HeaderPrivate +{ +public: + HeaderPrivate() : + frameSize(0), + version(4), + tagAlterPreservation(false), + fileAlterPreservation(false), + readOnly(false), + groupingIdentity(false), + compression(false), + encryption(false), + unsyncronisation(false), + dataLengthIndicator(false) + {} + + ByteVector frameID; + uint frameSize; + uint version; + + // flags + + bool tagAlterPreservation; + bool fileAlterPreservation; + bool readOnly; + bool groupingIdentity; + bool compression; + bool encryption; + bool unsyncronisation; + bool dataLengthIndicator; +}; + +//////////////////////////////////////////////////////////////////////////////// +// static members (Frame::Header) +//////////////////////////////////////////////////////////////////////////////// + +TagLib::uint Frame::Header::size() +{ + return size(4); +} + +TagLib::uint Frame::Header::size(uint version) +{ + switch(version) { + case 0: + case 1: + case 2: + return 6; + case 3: + case 4: + default: + return 10; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// public members (Frame::Header) +//////////////////////////////////////////////////////////////////////////////// + +Frame::Header::Header(const ByteVector &data, bool synchSafeInts) +{ + d = new HeaderPrivate; + setData(data, synchSafeInts); +} + +Frame::Header::Header(const ByteVector &data, uint version) +{ + d = new HeaderPrivate; + setData(data, version); +} + +Frame::Header::~Header() +{ + delete d; +} + +void Frame::Header::setData(const ByteVector &data, bool synchSafeInts) +{ + setData(data, uint(synchSafeInts ? 4 : 3)); +} + +void Frame::Header::setData(const ByteVector &data, uint version) +{ + d->version = version; + + switch(version) { + case 0: + case 1: + case 2: + { + // ID3v2.2 + + if(data.size() < 3) { + debug("You must at least specify a frame ID."); + return; + } + + // Set the frame ID -- the first three bytes + + d->frameID = data.mid(0, 3); + + // If the full header information was not passed in, do not continue to the + // steps to parse the frame size and flags. + + if(data.size() < 6) { + d->frameSize = 0; + return; + } + + d->frameSize = data.mid(3, 3).toUInt(); + + break; + } + case 3: + { + // ID3v2.3 + + if(data.size() < 4) { + debug("You must at least specify a frame ID."); + return; + } + + // Set the frame ID -- the first four bytes + + d->frameID = data.mid(0, 4); + + // If the full header information was not passed in, do not continue to the + // steps to parse the frame size and flags. + + if(data.size() < 10) { + d->frameSize = 0; + return; + } + + // Set the size -- the frame size is the four bytes starting at byte four in + // the frame header (structure 4) + + d->frameSize = data.mid(4, 4).toUInt(); + + { // read the first byte of flags + std::bitset<8> flags(data[8]); + d->tagAlterPreservation = flags[7]; // (structure 3.3.1.a) + d->fileAlterPreservation = flags[6]; // (structure 3.3.1.b) + d->readOnly = flags[5]; // (structure 3.3.1.c) + } + + { // read the second byte of flags + std::bitset<8> flags(data[9]); + d->compression = flags[7]; // (structure 3.3.1.i) + d->encryption = flags[6]; // (structure 3.3.1.j) + d->groupingIdentity = flags[5]; // (structure 3.3.1.k) + } + break; + } + case 4: + default: + { + // ID3v2.4 + + if(data.size() < 4) { + debug("You must at least specify a frame ID."); + return; + } + + // Set the frame ID -- the first four bytes + + d->frameID = data.mid(0, 4); + + // If the full header information was not passed in, do not continue to the + // steps to parse the frame size and flags. + + if(data.size() < 10) { + d->frameSize = 0; + return; + } + + // Set the size -- the frame size is the four bytes starting at byte four in + // the frame header (structure 4) + + d->frameSize = SynchData::toUInt(data.mid(4, 4)); + + { // read the first byte of flags + std::bitset<8> flags(data[8]); + d->tagAlterPreservation = flags[6]; // (structure 4.1.1.a) + d->fileAlterPreservation = flags[5]; // (structure 4.1.1.b) + d->readOnly = flags[4]; // (structure 4.1.1.c) + } + + { // read the second byte of flags + std::bitset<8> flags(data[9]); + d->groupingIdentity = flags[6]; // (structure 4.1.2.h) + d->compression = flags[3]; // (structure 4.1.2.k) + d->encryption = flags[2]; // (structure 4.1.2.m) + d->unsyncronisation = flags[1]; // (structure 4.1.2.n) + d->dataLengthIndicator = flags[0]; // (structure 4.1.2.p) + } + break; + } + } +} + +ByteVector Frame::Header::frameID() const +{ + return d->frameID; +} + +void Frame::Header::setFrameID(const ByteVector &id) +{ + d->frameID = id.mid(0, 4); +} + +TagLib::uint Frame::Header::frameSize() const +{ + return d->frameSize; +} + +void Frame::Header::setFrameSize(uint size) +{ + d->frameSize = size; +} + +TagLib::uint Frame::Header::version() const +{ + return d->version; +} + +bool Frame::Header::tagAlterPreservation() const +{ + return d->tagAlterPreservation; +} + +bool Frame::Header::fileAlterPreservation() const +{ + return d->fileAlterPreservation; +} + +bool Frame::Header::readOnly() const +{ + return d->readOnly; +} + +bool Frame::Header::groupingIdentity() const +{ + return d->groupingIdentity; +} + +bool Frame::Header::compression() const +{ + return d->compression; +} + +bool Frame::Header::encryption() const +{ + return d->encryption; +} + +bool Frame::Header::unsycronisation() const +{ + return d->unsyncronisation; +} + +bool Frame::Header::dataLengthIndicator() const +{ + return d->dataLengthIndicator; +} + +ByteVector Frame::Header::render() const +{ + ByteVector flags(2, char(0)); // just blank for the moment + + ByteVector v = d->frameID + SynchData::fromUInt(d->frameSize) + flags; + + return v; +} + +bool Frame::Header::frameAlterPreservation() const // deprecated +{ + return fileAlterPreservation(); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2frame.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2frame.h new file mode 100644 index 000000000..4e12dc210 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2frame.h @@ -0,0 +1,369 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V2FRAME_H +#define TAGLIB_ID3V2FRAME_H + +#include +#include + +namespace TagLib { + + namespace ID3v2 { + + class FrameFactory; + + //! ID3v2 frame implementation + + /*! + * This class is the main ID3v2 frame implementation. In ID3v2, a tag is + * split between a collection of frames (which are in turn split into fields + * (Structure, 4) + * (Frames). This class provides an API for + * gathering information about and modifying ID3v2 frames. Funtionallity + * specific to a given frame type is handed in one of the many subclasses. + */ + + class Frame + { + friend class FrameFactory; + + public: + /*! + * Destroys this Frame instance. + */ + virtual ~Frame(); + + /*! + * Returns the Frame ID (Structure, 4) + * (Frames, 4) + */ + ByteVector frameID() const; + + /*! + * Returns the size of the frame. + */ + uint size() const; + + /*! + * Returns the size of the frame header + * + * \deprecated This is only accurate for ID3v2.3 or ID3v2.4. Please use + * the call below which accepts an ID3v2 version number. In the next + * non-binary compatible release this will be made into a non-static + * member that checks the internal ID3v2 version. + */ + static uint headerSize(); // BIC: remove and make non-static + + /*! + * Returns the size of the frame header for the given ID3v2 version. + * + * \deprecated Please see the explanation above. + */ + static uint headerSize(uint version); // BIC: remove and make non-static + + /*! + * Sets the data that will be used as the frame. Since the length is not + * known before the frame has been parsed, this should just be a pointer to + * the first byte of the frame. It will determine the length internally + * and make that available through size(). + */ + void setData(const ByteVector &data); + + /*! + * Set the text of frame in the sanest way possible. This should only be + * reimplemented in frames where there is some logical mapping to text. + * + * \note If the frame type supports multiple text encodings, this will not + * change the text encoding of the frame; the string will be converted to + * that frame's encoding. Please use the specific APIs of the frame types + * to set the encoding if that is desired. + */ + virtual void setText(const String &text); + + /*! + * This returns the textual representation of the data in the frame. + * Subclasses must reimplement this method to provide a string + * representation of the frame's data. + */ + virtual String toString() const = 0; + + /*! + * Render the frame back to its binary format in a ByteVector. + */ + ByteVector render() const; + + /*! + * Returns the text delimiter that is used between fields for the string + * type \a t. + */ + static ByteVector textDelimiter(String::Type t); + + protected: + class Header; + + /*! + * Constructs an ID3v2 frame using \a data to read the header information. + * All other processing of \a data should be handled in a subclass. + * + * \note This need not contain anything more than a frame ID, but + * \e must constain at least that. + */ + explicit Frame(const ByteVector &data); + + /*! + * This creates an Frame using the header \a h. + * + * The ownership of this header will be assigned to the frame and the + * header will be deleted when the frame is destroyed. + */ + Frame(Header *h); + + /*! + * Returns a pointer to the frame header. + */ + Header *header() const; + + /*! + * Sets the header to \a h. If \a deleteCurrent is true, this will free + * the memory of the current header. + * + * The ownership of this header will be assigned to the frame and the + * header will be deleted when the frame is destroyed. + */ + void setHeader(Header *h, bool deleteCurrent = true); + + /*! + * Called by setData() to parse the frame data. It makes this information + * available through the public API. + */ + void parse(const ByteVector &data); + + /*! + * Called by parse() to parse the field data. It makes this information + * available through the public API. This must be overridden by the + * subclasses. + */ + virtual void parseFields(const ByteVector &data) = 0; + + /*! + * Render the field data back to a binary format in a ByteVector. This + * must be overridden by subclasses. + */ + virtual ByteVector renderFields() const = 0; + + /*! + * Returns a ByteVector containing the field data given the frame data. + * This correctly adjusts for the header size plus any additional frame + * data that's specified in the frame header flags. + */ + ByteVector fieldData(const ByteVector &frameData) const; + + private: + Frame(const Frame &); + Frame &operator=(const Frame &); + + class FramePrivate; + FramePrivate *d; + }; + + //! ID3v2 frame header implementation + + /*! + * The ID3v2 Frame Header (Structure, 4) + * + * Every ID3v2::Frame has an associated header that gives some general + * properties of the frame and also makes it possible to identify the frame + * type. + * + * As such when reading an ID3v2 tag ID3v2::FrameFactory first creates the + * frame headers and then creates the appropriate Frame subclass based on + * the type and attaches the header. + */ + + class Frame::Header + { + public: + /*! + * Construct a Frame Header based on \a data. \a data must at least + * contain a 4 byte frame ID, and optionally can contain flag data and the + * frame size. i.e. Just the frame id -- "TALB" -- is a valid value. + * + * \deprecated Please use the constructor below that accepts a version + * number. + */ + Header(const ByteVector &data, bool synchSafeInts); + + /*! + * Construct a Frame Header based on \a data. \a data must at least + * contain a 4 byte frame ID, and optionally can contain flag data and the + * frame size. i.e. Just the frame id -- "TALB" -- is a valid value. + * + * \a version should be the ID3v2 version of the tag. + */ + explicit Header(const ByteVector &data, uint version = 4); + + /*! + * Destroys this Header instance. + */ + virtual ~Header(); + + /*! + * Sets the data for the Header. + * + * \deprecated Please use the version below that accepts an ID3v2 version + * number. + */ + void setData(const ByteVector &data, bool synchSafeInts); + + /*! + * Sets the data for the Header. \a version should indicate the ID3v2 + * version number of the tag that this frame is contained in. + */ + void setData(const ByteVector &data, uint version = 4); + + /*! + * Returns the Frame ID (Structure, 4) + * (Frames, 4) + */ + ByteVector frameID() const; + + /*! + * Sets the frame's ID to \a id. Only the first four bytes of \a id will + * be used. + * + * \warning This method should in general be avoided. It exists simply to + * provide a mechanism for transforming frames from a deprecated frame type + * to a newer one -- i.e. TYER to TDRC from ID3v2.3 to ID3v2.4. + */ + void setFrameID(const ByteVector &id); + + /*! + * Returns the size of the frame data portion, as set when setData() was + * called or set explicity via setFrameSize(). + */ + uint frameSize() const; + + /*! + * Sets the size of the frame data portion. + */ + void setFrameSize(uint size); + + /*! + * Returns the ID3v2 version of the header (as passed in from the + * construction of the header). + */ + uint version() const; + + /*! + * Returns the size of the frame header in bytes. + * + * \deprecated Please use the version of this method that accepts a + * version. This is only accurate for ID3v2.3 and ID3v2.4. This will be + * removed in the next binary incompatible release (2.0) and will be + * replaced with a non-static method that checks the frame version. + */ + static uint size(); + + /*! + * Returns the size of the frame header in bytes for the ID3v2 version + * that's given. + * + * \deprecated Please see the explanation in the version above. + */ + static uint size(uint version); + + /*! + * Returns true if the flag for tag alter preservation is set. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool tagAlterPreservation() const; + + /*! + * Returns true if the flag for file alter preservation is set. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool fileAlterPreservation() const; + + /*! + * Returns true if the frame is meant to be read only. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool readOnly() const; + + /*! + * Returns true if the flag for the grouping identifity is set. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool groupingIdentity() const; + + /*! + * Returns true if compression is enabled for this frame. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool compression() const; + + /*! + * Returns true if encryption is enabled for this frame. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool encryption() const; + + /*! + * Returns true if unsyncronisation is enabled for this frame. + * + * \note This flag is currently ignored internally in TagLib. + */ + bool unsycronisation() const; + + /*! + * Returns true if the flag for a data lenght indicator is set. + */ + bool dataLengthIndicator() const; + + /*! + * Render the Header back to binary format in a ByteVector. + */ + ByteVector render() const; + + /*! + * @deprecated + */ + bool frameAlterPreservation() const; + + private: + Header(const Header &); + Header &operator=(const Header &); + + class HeaderPrivate; + HeaderPrivate *d; + }; + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2framefactory.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2framefactory.cpp new file mode 100644 index 000000000..3fc976a5c --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2framefactory.cpp @@ -0,0 +1,309 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include + +#include "id3v2framefactory.h" + +#include "frames/attachedpictureframe.h" +#include "frames/commentsframe.h" +#include "frames/relativevolumeframe.h" +#include "frames/textidentificationframe.h" +#include "frames/uniquefileidentifierframe.h" +#include "frames/unknownframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class FrameFactory::FrameFactoryPrivate +{ +public: + FrameFactoryPrivate() : + defaultEncoding(String::Latin1), + useDefaultEncoding(false) {} + + String::Type defaultEncoding; + bool useDefaultEncoding; +}; + +FrameFactory *FrameFactory::factory = 0; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +FrameFactory *FrameFactory::instance() +{ + if(!factory) + factory = new FrameFactory; + return factory; +} + +Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const +{ + return createFrame(data, uint(synchSafeInts ? 4 : 3)); +} + +Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const +{ + Frame::Header *header = new Frame::Header(data, version); + ByteVector frameID = header->frameID(); + + // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1 + // characters. Also make sure that there is data in the frame. + + if(!frameID.size() == (version < 3 ? 3 : 4) || header->frameSize() <= 0) { + delete header; + return 0; + } + + for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { + if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) { + delete header; + return 0; + } + } + + // TagLib doesn't mess with encrypted frames, so just treat them + // as unknown frames. + +#if HAVE_ZLIB == 0 + if(header->compression()) { + debug("Compressed frames are currently not supported."); + return new UnknownFrame(data, header); + } +#endif + if(header->encryption()) { + debug("Encrypted frames are currently not supported."); + return new UnknownFrame(data, header); + } + + if(!updateFrame(header)) { + delete header; + return 0; + } + + // This is where things get necissarily nasty. Here we determine which + // Frame subclass (or if none is found simply an Frame) based + // on the frame ID. Since there are a lot of possibilities, that means + // a lot of if blocks. + + // Text Identification (frames 4.2) + + if(frameID.startsWith("T")) { + TextIdentificationFrame *f = frameID != "TXXX" + ? new TextIdentificationFrame(data, header) + : new UserTextIdentificationFrame(data, header); + + if(d->useDefaultEncoding) + f->setTextEncoding(d->defaultEncoding); + return f; + } + + // Comments (frames 4.10) + + if(frameID == "COMM") { + CommentsFrame *f = new CommentsFrame(data, header); + if(d->useDefaultEncoding) + f->setTextEncoding(d->defaultEncoding); + return f; + } + + // Attached Picture (frames 4.14) + + if(frameID == "APIC") { + AttachedPictureFrame *f = new AttachedPictureFrame(data, header); + if(d->useDefaultEncoding) + f->setTextEncoding(d->defaultEncoding); + return f; + } + + // Relative Volume Adjustment (frames 4.11) + + if(frameID == "RVA2") + return new RelativeVolumeFrame(data, header); + + // Unique File Identifier (frames 4.1) + + if(frameID == "UFID") + return new UniqueFileIdentifierFrame(data, header); + + return new UnknownFrame(data, header); +} + +String::Type FrameFactory::defaultTextEncoding() const +{ + return d->defaultEncoding; +} + +void FrameFactory::setDefaultTextEncoding(String::Type encoding) +{ + d->useDefaultEncoding = true; + d->defaultEncoding = encoding; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +FrameFactory::FrameFactory() +{ + d = new FrameFactoryPrivate; +} + +FrameFactory::~FrameFactory() +{ + delete d; +} + +bool FrameFactory::updateFrame(Frame::Header *header) const +{ + TagLib::ByteVector frameID = header->frameID(); + + switch(header->version()) { + + case 2: // ID3v2.2 + { + if(frameID == "CRM" || + frameID == "EQU" || + frameID == "LNK" || + frameID == "RVA" || + frameID == "TIM" || + frameID == "TSI") + { + debug("ID3v2.4 no longer supports the frame type " + String(frameID) + + ". It will be discarded from the tag."); + return false; + } + + // ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of + // the frames to their 4 byte ID3v2.4 equivalent. + + convertFrame("BUF", "RBUF", header); + convertFrame("CNT", "PCNT", header); + convertFrame("COM", "COMM", header); + convertFrame("CRA", "AENC", header); + convertFrame("ETC", "ETCO", header); + convertFrame("GEO", "GEOB", header); + convertFrame("IPL", "TIPL", header); + convertFrame("MCI", "MCDI", header); + convertFrame("MLL", "MLLT", header); + convertFrame("PIC", "APIC", header); + convertFrame("POP", "POPM", header); + convertFrame("REV", "RVRB", header); + convertFrame("SLT", "SYLT", header); + convertFrame("STC", "SYTC", header); + convertFrame("TAL", "TALB", header); + convertFrame("TBP", "TBPM", header); + convertFrame("TCM", "TCOM", header); + convertFrame("TCO", "TCON", header); + convertFrame("TCR", "TCOP", header); + convertFrame("TDA", "TDRC", header); + convertFrame("TDY", "TDLY", header); + convertFrame("TEN", "TENC", header); + convertFrame("TFT", "TFLT", header); + convertFrame("TKE", "TKEY", header); + convertFrame("TLA", "TLAN", header); + convertFrame("TLE", "TLEN", header); + convertFrame("TMT", "TMED", header); + convertFrame("TOA", "TOAL", header); + convertFrame("TOF", "TOFN", header); + convertFrame("TOL", "TOLY", header); + convertFrame("TOR", "TDOR", header); + convertFrame("TOT", "TOAL", header); + convertFrame("TP1", "TPE1", header); + convertFrame("TP2", "TPE2", header); + convertFrame("TP3", "TPE3", header); + convertFrame("TP4", "TPE4", header); + convertFrame("TPA", "TPOS", header); + convertFrame("TPB", "TPUB", header); + convertFrame("TRC", "TSRC", header); + convertFrame("TRD", "TDRC", header); + convertFrame("TRK", "TRCK", header); + convertFrame("TSS", "TSSE", header); + convertFrame("TT1", "TIT1", header); + convertFrame("TT2", "TIT2", header); + convertFrame("TT3", "TIT3", header); + convertFrame("TXT", "TOLY", header); + convertFrame("TXX", "TXXX", header); + convertFrame("TYE", "TDRC", header); + convertFrame("UFI", "UFID", header); + convertFrame("ULT", "USLT", header); + convertFrame("WAF", "WOAF", header); + convertFrame("WAR", "WOAR", header); + convertFrame("WAS", "WOAS", header); + convertFrame("WCM", "WCOM", header); + convertFrame("WCP", "WCOP", header); + convertFrame("WPB", "WPUB", header); + convertFrame("WXX", "WXXX", header); + + break; + } + + case 3: // ID3v2.3 + { + if(frameID == "EQUA" || + frameID == "RVAD" || + frameID == "TIME" || + frameID == "TRDA" || + frameID == "TSIZ") + { + debug("ID3v2.4 no longer supports the frame type " + String(frameID) + + ". It will be discarded from the tag."); + return false; + } + + convertFrame("TDAT", "TDRC", header); + convertFrame("TORY", "TDOR", header); + convertFrame("TYER", "TDRC", header); + + break; + } + + default: + + // This should catch a typo that existed in TagLib up to and including + // version 1.1 where TRDC was used for the year rather than TDRC. + + convertFrame("TRDC", "TDRC", header); + break; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void FrameFactory::convertFrame(const char *from, const char *to, + Frame::Header *header) const +{ + if(header->frameID() != from) + return; + + // debug("ID3v2.4 no longer supports the frame type " + String(from) + " It has" + + // "been converted to the type " + String(to) + "."); + + header->setFrameID(to); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2framefactory.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2framefactory.h new file mode 100644 index 000000000..4a0d11b4b --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2framefactory.h @@ -0,0 +1,140 @@ + /*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V2FRAMEFACTORY_H +#define TAGLIB_ID3V2FRAMEFACTORY_H + +#include +#include "id3v2frame.h" + +namespace TagLib { + + namespace ID3v2 { + + //! A factory for creating ID3v2 frames + + /*! + * This factory abstracts away the frame creation process and instantiates + * the appropriate ID3v2::Frame subclasses based on the contents of the + * data. + * + * Reimplementing this factory is the key to adding support for frame types + * not directly supported by TagLib to your application. To do so you would + * subclass this factory reimplement createFrame(). Then by setting your + * factory to be the default factory in ID3v2::Tag constructor or with + * MPEG::File::setID3v2FrameFactory() you can implement behavior that will + * allow for new ID3v2::Frame subclasses (also provided by you) to be used. + * + * This implements both abstract factory and singleton patterns + * of which more information is available on the web and in software design + * textbooks (Notably Design Patters). + */ + + class FrameFactory + { + public: + static FrameFactory *instance(); + /*! + * Create a frame based on \a data. \a synchSafeInts should only be set + * false if we are parsing an old tag (v2.3 or older) that does not support + * synchsafe ints. + * + * \deprecated Please use the method below that accepts an ID3 version + * number in new code. + */ + Frame *createFrame(const ByteVector &data, bool synchSafeInts) const; + + /*! + * Create a frame based on \a data. \a version should indicate the ID3v2 + * version of the tag. As ID3v2.4 is the most current version of the + * standard 4 is the default. + */ + // BIC: make virtual + Frame *createFrame(const ByteVector &data, uint version = 4) const; + + /*! + * Returns the default text encoding for text frames. If setTextEncoding() + * has not been explicitly called this will only be used for new text + * frames. However, if this value has been set explicitly all frames will be + * converted to this type (unless it's explitly set differently for the + * individual frame) when being rendered. + * + * \see setDefaultTextEncoding() + */ + String::Type defaultTextEncoding() const; + + /*! + * Set the default text encoding for all text frames that are created to + * \a encoding. If no value is set the frames with either default to the + * encoding type that was parsed and new frames default to Latin1. + * + * \see defaultTextEncoding() + */ + void setDefaultTextEncoding(String::Type encoding); + + protected: + /*! + * Constructs a frame factory. Because this is a singleton this method is + * protected, but may be used for subclasses. + */ + FrameFactory(); + + /*! + * Destroys the frame factory. In most cases this will never be called (as + * is typical of singletons). + */ + virtual ~FrameFactory(); + + /*! + * This method checks for compliance to the current ID3v2 standard (2.4) + * and does nothing in the common case. However if a frame is found that + * is not compatible with the current standard, this method either updates + * the frame or indicates that it should be discarded. + * + * This method with return true (with or without changes to the frame) if + * this frame should be kept or false if it should be discarded. + * + * See the id3v2.4.0-changes.txt document for further information. + */ + virtual bool updateFrame(Frame::Header *header) const; + + private: + FrameFactory(const FrameFactory &); + FrameFactory &operator=(const FrameFactory &); + + /*! + * This method is used internally to convert a frame from ID \a from to ID + * \a to. If the frame matches the \a from pattern and converts the frame + * ID in the \a header or simply does nothing if the frame ID does not match. + */ + void convertFrame(const char *from, const char *to, + Frame::Header *header) const; + + static FrameFactory *factory; + + class FrameFactoryPrivate; + FrameFactoryPrivate *d; + }; + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2header.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2header.cpp new file mode 100644 index 000000000..4ed09e8a5 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2header.cpp @@ -0,0 +1,227 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include +#include + +#include "id3v2header.h" +#include "id3v2footer.h" +#include "id3v2synchdata.h" + +using namespace TagLib; +using namespace ID3v2; + +class Header::HeaderPrivate +{ +public: + HeaderPrivate() : majorVersion(0), + revisionNumber(0), + unsynchronisation(false), + extendedHeader(false), + experimentalIndicator(false), + footerPresent(false), + tagSize(0) {} + + ~HeaderPrivate() {} + + uint majorVersion; + uint revisionNumber; + + bool unsynchronisation; + bool extendedHeader; + bool experimentalIndicator; + bool footerPresent; + + uint tagSize; + + static const uint size = 10; +}; + +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +TagLib::uint Header::size() +{ + return HeaderPrivate::size; +} + +ByteVector Header::fileIdentifier() +{ + return ByteVector::fromCString("ID3"); +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Header::Header() +{ + d = new HeaderPrivate; +} + +Header::Header(const ByteVector &data) +{ + d = new HeaderPrivate; + parse(data); +} + +Header::~Header() +{ + delete d; +} + +TagLib::uint Header::majorVersion() const +{ + return d->majorVersion; +} + +TagLib::uint Header::revisionNumber() const +{ + return d->revisionNumber; +} + +bool Header::unsynchronisation() const +{ + return d->unsynchronisation; +} + +bool Header::extendedHeader() const +{ + return d->extendedHeader; +} + +bool Header::experimentalIndicator() const +{ + return d->experimentalIndicator; +} + +bool Header::footerPresent() const +{ + return d->footerPresent; +} + +TagLib::uint Header::tagSize() const +{ + return d->tagSize; +} + +TagLib::uint Header::completeTagSize() const +{ + if(d->footerPresent) + return d->tagSize + d->size + Footer::size(); + else + return d->tagSize + d->size; +} + +void Header::setTagSize(uint s) +{ + d->tagSize = s; +} + +void Header::setData(const ByteVector &data) +{ + parse(data); +} + +ByteVector Header::render() const +{ + ByteVector v; + + // add the file identifier -- "ID3" + v.append(fileIdentifier()); + + // add the version number -- we always render a 2.4.0 tag regardless of what + // the tag originally was. + + v.append(char(4)); + v.append(char(0)); + + // render and add the flags + std::bitset<8> flags; + + flags[7] = d->unsynchronisation; + flags[6] = d->extendedHeader; + flags[5] = d->experimentalIndicator; + flags[4] = d->footerPresent; + + v.append(char(flags.to_ulong())); + + // add the size + v.append(SynchData::fromUInt(d->tagSize)); + + return v; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void Header::parse(const ByteVector &data) +{ + if(data.size() < size()) + return; + + + // do some sanity checking -- even in ID3v2.3.0 and less the tag size is a + // synch-safe integer, so all bytes must be less than 128. If this is not + // true then this is an invalid tag. + + // note that we're doing things a little out of order here -- the size is + // later in the bytestream than the version + + ByteVector sizeData = data.mid(6, 4); + + if(sizeData.size() != 4) { + d->tagSize = 0; + debug("TagLib::ID3v2::Header::parse() - The tag size as read was 0 bytes!"); + return; + } + + for(ByteVector::Iterator it = sizeData.begin(); it != sizeData.end(); it++) { + if(uchar(*it) >= 128) { + d->tagSize = 0; + debug("TagLib::ID3v2::Header::parse() - One of the size bytes in the id3v2 header was greater than the allowed 128."); + return; + } + } + + // The first three bytes, data[0..2], are the File Identifier, "ID3". (structure 3.1 "file identifier") + + // Read the version number from the fourth and fifth bytes. + d->majorVersion = data[3]; // (structure 3.1 "major version") + d->revisionNumber = data[4]; // (structure 3.1 "revision number") + + // Read the flags, the first four bits of the sixth byte. + std::bitset<8> flags(data[5]); + + d->unsynchronisation = flags[7]; // (structure 3.1.a) + d->extendedHeader = flags[6]; // (structure 3.1.b) + d->experimentalIndicator = flags[5]; // (structure 3.1.c) + d->footerPresent = flags[4]; // (structure 3.1.d) + + // Get the size from the remaining four bytes (read above) + + d->tagSize = SynchData::toUInt(sizeData); // (structure 3.1 "size") +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2header.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2header.h new file mode 100644 index 000000000..56d2fc8aa --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2header.h @@ -0,0 +1,159 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V2HEADER_H +#define TAGLIB_ID3V2HEADER_H + +#include + +namespace TagLib { + + namespace ID3v2 { + + //! An implementation of ID3v2 headers + + /*! + * This class implements ID3v2 headers. It attempts to follow, both + * semantically and programatically, the structure specified in + * the ID3v2 standard. The API is based on the properties of ID3v2 headers + * specified there. If any of the terms used in this documentation are + * unclear please check the specification in the linked section. + * (Structure, 3.1) + */ + + class Header + { + public: + /*! + * Constructs an empty ID3v2 header. + */ + Header(); + + /*! + * Constructs an ID3v2 header based on \a data. parse() is called + * immediately. + */ + Header(const ByteVector &data); + + /*! + * Destroys the header. + */ + virtual ~Header(); + + /*! + * Returns the major version number. (Note: This is the 4, not the 2 in + * ID3v2.4.0. The 2 is implied.) + */ + uint majorVersion() const; + + /*! + * Returns the revision number. (Note: This is the 0, not the 4 in + * ID3v2.4.0. The 2 is implied.) + */ + uint revisionNumber() const; + + /*! + * Returns true if unsynchronisation has been applied to all frames. + */ + bool unsynchronisation() const; + + /*! + * Returns true if an extended header is present in the tag. + */ + bool extendedHeader() const; + + /*! + * Returns true if the experimental indicator flag is set. + */ + bool experimentalIndicator() const; + + /*! + * Returns true if a footer is present in the tag. + */ + bool footerPresent() const; + /*! + * Returns the tag size in bytes. This is the size of the frame content. + * The size of the \e entire tag will be this plus the header size (10 + * bytes) and, if present, the footer size (potentially another 10 bytes). + * + * \note This is the value as read from the header to which TagLib attempts + * to provide an API to; it was not a design decision on the part of TagLib + * to not include the mentioned portions of the tag in the \e size. + * + * \see completeTagSize() + */ + uint tagSize() const; + + /*! + * Returns the tag size, including the header and, if present, the footer + * size. + * + * \see tagSize() + */ + uint completeTagSize() const; + + /*! + * Set the tag size to \a s. + * \see tagSize() + */ + void setTagSize(uint s); + + /*! + * Returns the size of the header. Presently this is always 10 bytes. + */ + static uint size(); + + /*! + * Returns the string used to identify and ID3v2 tag inside of a file. + * Presently this is always "ID3". + */ + static ByteVector fileIdentifier(); + + /*! + * Sets the data that will be used as the extended header. 10 bytes, + * starting from \a data will be used. + */ + void setData(const ByteVector &data); + + /*! + * Renders the Header back to binary format. + */ + ByteVector render() const; + + protected: + /*! + * Called by setData() to parse the header data. It makes this information + * available through the public API. + */ + void parse(const ByteVector &data); + + private: + Header(const Header &); + Header &operator=(const Header &); + + class HeaderPrivate; + HeaderPrivate *d; + }; + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2synchdata.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2synchdata.cpp new file mode 100644 index 000000000..ccb6046f5 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2synchdata.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include "id3v2synchdata.h" + +using namespace TagLib; +using namespace ID3v2; + +TagLib::uint SynchData::toUInt(const ByteVector &data) +{ + uint sum = 0; + int last = data.size() > 4 ? 3 : data.size() - 1; + + for(int i = 0; i <= last; i++) + sum |= (data[i] & 0x7f) << ((last - i) * 7); + + return sum; +} + +ByteVector SynchData::fromUInt(uint value) +{ + ByteVector v(4, 0); + + for(int i = 0; i < 4; i++) + v[i] = uchar(value >> ((3 - i) * 7) & 0x7f); + + return v; +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2synchdata.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2synchdata.h new file mode 100644 index 000000000..80a462f1b --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2synchdata.h @@ -0,0 +1,61 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V2SYNCHDATA_H +#define TAGLIB_ID3V2SYNCHDATA_H + +#include +#include + +namespace TagLib { + + namespace ID3v2 { + + //! A few functions for ID3v2 synch safe integer conversion + + /*! + * In the ID3v2.4 standard most integer values are encoded as "synch safe" + * integers which are encoded in such a way that they will not give false + * MPEG syncs and confuse MPEG decoders. This namespace provides some + * methods for converting to and from these values to ByteVectors for + * things rendering and parsing ID3v2 data. + */ + + namespace SynchData + { + /*! + * This returns the unsigned integer value of \a data where \a data is a + * ByteVector that contains a \e synchsafe integer (Structure, + * 6.2). The default \a length of + * 4 is used if another value is not specified. + */ + uint toUInt(const ByteVector &data); + + /*! + * Returns a 4 byte (32 bit) synchsafe integer based on \a value. + */ + ByteVector fromUInt(uint value); + } + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2tag.cpp b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2tag.cpp new file mode 100644 index 000000000..00249b81e --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2tag.cpp @@ -0,0 +1,464 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "id3v2tag.h" +#include "id3v2header.h" +#include "id3v2extendedheader.h" +#include "id3v2footer.h" + +#include "id3v1genres.h" + +#include "frames/textidentificationframe.h" +#include "frames/commentsframe.h" + +using namespace TagLib; +using namespace ID3v2; + +class ID3v2::Tag::TagPrivate +{ +public: + TagPrivate() : file(0), tagOffset(-1), extendedHeader(0), footer(0), paddingSize(0) + { + frameList.setAutoDelete(true); + } + ~TagPrivate() + { + delete extendedHeader; + delete footer; + } + + File *file; + long tagOffset; + const FrameFactory *factory; + + Header header; + ExtendedHeader *extendedHeader; + Footer *footer; + + int paddingSize; + + FrameListMap frameListMap; + FrameList frameList; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +ID3v2::Tag::Tag() : TagLib::Tag() +{ + d = new TagPrivate; + d->factory = FrameFactory::instance(); +} + +ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) : + TagLib::Tag() +{ + d = new TagPrivate; + + d->file = file; + d->tagOffset = tagOffset; + d->factory = factory; + + read(); +} + +ID3v2::Tag::~Tag() +{ + delete d; +} + + +String ID3v2::Tag::title() const +{ + if(!d->frameListMap["TIT2"].isEmpty()) + return d->frameListMap["TIT2"].front()->toString(); + return String::null; +} + +String ID3v2::Tag::artist() const +{ + if(!d->frameListMap["TPE1"].isEmpty()) + return d->frameListMap["TPE1"].front()->toString(); + return String::null; +} + +String ID3v2::Tag::album() const +{ + if(!d->frameListMap["TALB"].isEmpty()) + return d->frameListMap["TALB"].front()->toString(); + return String::null; +} + +String ID3v2::Tag::comment() const +{ + if(!d->frameListMap["COMM"].isEmpty()) + return d->frameListMap["COMM"].front()->toString(); + return String::null; +} + +String ID3v2::Tag::genre() const +{ + // TODO: In the next major version (TagLib 2.0) a list of multiple genres + // should be separated by " / " instead of " ". For the moment to keep + // the behavior the same as released versions it is being left with " ". + + if(!d->frameListMap["TCON"].isEmpty() && + dynamic_cast(d->frameListMap["TCON"].front())) + { + Frame *frame = d->frameListMap["TCON"].front(); + + // ID3v2.4 lists genres as the fields in its frames field list. If the field + // is simply a number it can be assumed that it is an ID3v1 genre number. + // Here was assume that if an ID3v1 string is present that it should be + // appended to the genre string. Multiple fields will be appended as the + // string is built. + + if(d->header.majorVersion() == 4) { + TextIdentificationFrame *f = static_cast(frame); + StringList fields = f->fieldList(); + + String genreString; + bool hasNumber = false; + + for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) { + bool isNumber = true; + for(String::ConstIterator charIt = (*it).begin(); + isNumber && charIt != (*it).end(); + ++charIt) + { + isNumber = *charIt >= '0' && *charIt <= '9'; + } + + if(!genreString.isEmpty()) + genreString.append(' '); + + if(isNumber) { + int number = (*it).toInt(); + if(number >= 0 && number <= 255) { + hasNumber = true; + genreString.append(ID3v1::genre(number)); + } + } + else + genreString.append(*it); + } + if(hasNumber) + return genreString; + } + + String s = frame->toString(); + + // ID3v2.3 "content type" can contain a ID3v1 genre number in parenthesis at + // the beginning of the field. If this is all that the field contains, do a + // translation from that number to the name and return that. If there is a + // string folloing the ID3v1 genre number, that is considered to be + // authoritative and we return that instead. Or finally, the field may + // simply be free text, in which case we just return the value. + + int closing = s.find(")"); + if(s.substr(0, 1) == "(" && closing > 0) { + if(closing == int(s.size() - 1)) + return ID3v1::genre(s.substr(1, s.size() - 2).toInt()); + else + return s.substr(closing + 1); + } + return s; + } + return String::null; +} + +TagLib::uint ID3v2::Tag::year() const +{ + if(!d->frameListMap["TDRC"].isEmpty()) + return d->frameListMap["TDRC"].front()->toString().substr(0, 4).toInt(); + return 0; +} + +TagLib::uint ID3v2::Tag::track() const +{ + if(!d->frameListMap["TRCK"].isEmpty()) + return d->frameListMap["TRCK"].front()->toString().toInt(); + return 0; +} + +void ID3v2::Tag::setTitle(const String &s) +{ + setTextFrame("TIT2", s); +} + +void ID3v2::Tag::setArtist(const String &s) +{ + setTextFrame("TPE1", s); +} + +void ID3v2::Tag::setAlbum(const String &s) +{ + setTextFrame("TALB", s); +} + +void ID3v2::Tag::setComment(const String &s) +{ + if(s.isEmpty()) { + removeFrames("COMM"); + return; + } + + if(!d->frameListMap["COMM"].isEmpty()) + d->frameListMap["COMM"].front()->setText(s); + else { + CommentsFrame *f = new CommentsFrame(d->factory->defaultTextEncoding()); + addFrame(f); + f->setText(s); + } +} + +void ID3v2::Tag::setGenre(const String &s) +{ + if(s.isEmpty()) { + removeFrames("TCON"); + return; + } + + int index = ID3v1::genreIndex(s); + + if(index != 255) + setTextFrame("TCON", String::number(index)); + else + setTextFrame("TCON", s); +} + +void ID3v2::Tag::setYear(uint i) +{ + if(i <= 0) { + removeFrames("TDRC"); + return; + } + setTextFrame("TDRC", String::number(i)); +} + +void ID3v2::Tag::setTrack(uint i) +{ + if(i <= 0) { + removeFrames("TRCK"); + return; + } + setTextFrame("TRCK", String::number(i)); +} + +bool ID3v2::Tag::isEmpty() const +{ + return d->frameList.isEmpty(); +} + +Header *ID3v2::Tag::header() const +{ + return &(d->header); +} + +ExtendedHeader *ID3v2::Tag::extendedHeader() const +{ + return d->extendedHeader; +} + +Footer *ID3v2::Tag::footer() const +{ + return d->footer; +} + +const FrameListMap &ID3v2::Tag::frameListMap() const +{ + return d->frameListMap; +} + +const FrameList &ID3v2::Tag::frameList() const +{ + return d->frameList; +} + +const FrameList &ID3v2::Tag::frameList(const ByteVector &frameID) const +{ + return d->frameListMap[frameID]; +} + +void ID3v2::Tag::addFrame(Frame *frame) +{ + d->frameList.append(frame); + d->frameListMap[frame->frameID()].append(frame); +} + +void ID3v2::Tag::removeFrame(Frame *frame, bool del) +{ + // remove the frame from the frame list + FrameList::Iterator it = d->frameList.find(frame); + d->frameList.erase(it); + + // ...and from the frame list map + it = d->frameListMap[frame->frameID()].find(frame); + d->frameListMap[frame->frameID()].erase(it); + + // ...and delete as desired + if(del) + delete *it; +} + +void ID3v2::Tag::removeFrames(const ByteVector &id) +{ + FrameList l = d->frameListMap[id]; + for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) + removeFrame(*it, true); +} + +ByteVector ID3v2::Tag::render() const +{ + // We need to render the "tag data" first so that we have to correct size to + // render in the tag's header. The "tag data" -- everything that is included + // in ID3v2::Header::tagSize() -- includes the extended header, frames and + // padding, but does not include the tag's header or footer. + + ByteVector tagData; + + // TODO: Render the extended header. + + // Loop through the frames rendering them and adding them to the tagData. + + for(FrameList::Iterator it = d->frameList.begin(); it != d->frameList.end(); it++) + tagData.append((*it)->render()); + + // Compute the amount of padding, and append that to tagData. + + uint paddingSize = 0; + uint originalSize = d->header.tagSize(); + + if(tagData.size() < originalSize) + paddingSize = originalSize - tagData.size(); + else + paddingSize = 1024; + + tagData.append(ByteVector(paddingSize, char(0))); + + // Set the tag size. + d->header.setTagSize(tagData.size()); + + // TODO: This should eventually include d->footer->render(). + return d->header.render() + tagData; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void ID3v2::Tag::read() +{ + if(d->file && d->file->isOpen()) { + + d->file->seek(d->tagOffset); + d->header.setData(d->file->readBlock(Header::size())); + + // if the tag size is 0, then this is an invalid tag (tags must contain at + // least one frame) + + if(d->header.tagSize() == 0) + return; + + parse(d->file->readBlock(d->header.tagSize())); + } +} + +void ID3v2::Tag::parse(const ByteVector &data) +{ + uint frameDataPosition = 0; + uint frameDataLength = data.size(); + + // check for extended header + + if(d->header.extendedHeader()) { + if(!d->extendedHeader) + d->extendedHeader = new ExtendedHeader; + d->extendedHeader->setData(data); + if(d->extendedHeader->size() <= data.size()) { + frameDataPosition += d->extendedHeader->size(); + frameDataLength -= d->extendedHeader->size(); + } + } + + // check for footer -- we don't actually need to parse it, as it *must* + // contain the same data as the header, but we do need to account for its + // size. + + if(d->header.footerPresent() && Footer::size() <= frameDataLength) + frameDataLength -= Footer::size(); + + // parse frames + + // Make sure that there is at least enough room in the remaining frame data for + // a frame header. + + while(frameDataPosition < frameDataLength - Frame::headerSize(d->header.majorVersion())) { + + // If the next data is position is 0, assume that we've hit the padding + // portion of the frame data. + + if(data.at(frameDataPosition) == 0) { + if(d->header.footerPresent()) + debug("Padding *and* a footer found. This is not allowed by the spec."); + + d->paddingSize = frameDataLength - frameDataPosition; + return; + } + + Frame *frame = d->factory->createFrame(data.mid(frameDataPosition), + d->header.majorVersion()); + + if(!frame) + return; + + // Checks to make sure that frame parsed correctly. + + if(frame->size() <= 0) { + delete frame; + return; + } + + frameDataPosition += frame->size() + Frame::headerSize(d->header.majorVersion()); + addFrame(frame); + } +} + +void ID3v2::Tag::setTextFrame(const ByteVector &id, const String &value) +{ + if(value.isEmpty()) { + removeFrames(id); + return; + } + + if(!d->frameListMap[id].isEmpty()) + d->frameListMap[id].front()->setText(value); + else { + const String::Type encoding = d->factory->defaultTextEncoding(); + TextIdentificationFrame *f = new TextIdentificationFrame(id, encoding); + addFrame(f); + f->setText(value); + } +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2tag.h b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2tag.h new file mode 100644 index 000000000..5606c9d9c --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/id3v2/id3v2tag.h @@ -0,0 +1,295 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_ID3V2TAG_H +#define TAGLIB_ID3V2TAG_H + +#include +#include +#include +#include +#include + +#include "id3v2framefactory.h" + +namespace TagLib { + + class File; + + //! An ID3v2 implementation + + /*! + * This is a relatively complete and flexible framework for working with ID3v2 + * tags. + * + * \see ID3v2::Tag + */ + + namespace ID3v2 { + + class Header; + class ExtendedHeader; + class Footer; + + typedef List FrameList; + typedef Map FrameListMap; + + //! The main class in the ID3v2 implementation + + /*! + * This is the main class in the ID3v2 implementation. It serves two + * functions. This first, as is obvious from the public API, is to provide a + * container for the other ID3v2 related classes. In addition, through the + * read() and parse() protected methods, it provides the most basic level of + * parsing. In these methods the ID3v2 tag is extracted from the file and + * split into data components. + * + * ID3v2 tags have several parts, TagLib attempts to provide an interface + * for them all. header(), footer() and extendedHeader() corespond to those + * data structures in the ID3v2 standard and the APIs for the classes that + * they return attempt to reflect this. + * + * Also ID3v2 tags are built up from a list of frames, which are in turn + * have a header and a list of fields. TagLib provides two ways of accessing + * the list of frames that are in a given ID3v2 tag. The first is simply + * via the frameList() method. This is just a list of pointers to the frames. + * The second is a map from the frame type -- i.e. "COMM" for comments -- and + * a list of frames of that type. (In some cases ID3v2 allows for multiple + * frames of the same type, hence this being a map to a list rather than just + * a map to an individual frame.) + * + * More information on the structure of frames can be found in the ID3v2::Frame + * class. + * + * read() and parse() pass binary data to the other ID3v2 class structures, + * they do not handle parsing of flags or fields, for instace. Those are + * handled by similar functions within those classes. + * + * \note All pointers to data structures within the tag will become invalid + * when the tag is destroyed. + * + * \warning Dealing with the nasty details of ID3v2 is not for the faint of + * heart and should not be done without much meditation on the spec. It's + * rather long, but if you're planning on messing with this class and others + * that deal with the details of ID3v2 (rather than the nice, safe, abstract + * TagLib::Tag and friends), it's worth your time to familiarize yourself + * with said spec (which is distrubuted with the TagLib sources). TagLib + * tries to do most of the work, but with a little luck, you can still + * convince it to generate invalid ID3v2 tags. The APIs for ID3v2 assume a + * working knowledge of ID3v2 structure. You're been warned. + */ + + class Tag : public TagLib::Tag + { + public: + /*! + * Constructs an empty ID3v2 tag. + * + * \note You must create at least one frame for this tag to be valid. + */ + Tag(); + + /*! + * Constructs an ID3v2 tag read from \a file starting at \a tagOffset. + * \a factory specifies which FrameFactory will be used for the + * construction of new frames. + * + * \note You should be able to ignore the \a factory parameter in almost + * all situations. You would want to specify your own FrameFactory + * subclass in the case that you are extending TagLib to support additional + * frame types, which would be incorperated into your factory. + * + * \see FrameFactory + */ + Tag(File *file, long tagOffset, + const FrameFactory *factory = FrameFactory::instance()); + + /*! + * Destroys this Tag instance. + */ + virtual ~Tag(); + + // Reimplementations. + + virtual String title() const; + virtual String artist() const; + virtual String album() const; + virtual String comment() const; + virtual String genre() const; + virtual uint year() const; + virtual uint track() const; + + virtual void setTitle(const String &s); + virtual void setArtist(const String &s); + virtual void setAlbum(const String &s); + virtual void setComment(const String &s); + virtual void setGenre(const String &s); + virtual void setYear(uint i); + virtual void setTrack(uint i); + + virtual bool isEmpty() const; + + /*! + * Returns a pointer to the tag's header. + */ + Header *header() const; + + /*! + * Returns a pointer to the tag's extended header or null if there is no + * extended header. + */ + ExtendedHeader *extendedHeader() const; + + /*! + * Returns a pointer to the tag's footer or null if there is no footer. + * + * \deprecated I don't see any reason to keep this around since there's + * nothing useful to be retrieved from the footer, but well, again, I'm + * prone to change my mind, so this gets to stay around until near a + * release. + */ + Footer *footer() const; + + /*! + * Returns a reference to the frame list map. This is an FrameListMap of + * all of the frames in the tag. + * + * This is the most convenient structure for accessing the tag's frames. + * Many frame types allow multiple instances of the same frame type so this + * is a map of lists. In most cases however there will only be a single + * frame of a certain type. + * + * Let's say for instance that you wanted to access the frame for total + * beats per minute -- the TBPM frame. + * + * \code + * TagLib::MPEG::File f("foo.mp3"); + * + * // Check to make sure that it has an ID3v2 tag + * + * if(f.ID3v2Tag()) { + * + * // Get the list of frames for a specific frame type + * + * TagLib::ID3v2::FrameList l = f.ID3v2Tag()->frameListMap()["TBPM"]; + * + * if(!l.isEmpty()) + * std::cout << l.front().toString() << std::endl; + * } + * + * \endcode + * + * \warning You should not modify this data structure directly, instead + * use addFrame() and removeFrame(). + * + * \see frameList() + */ + const FrameListMap &frameListMap() const; + + /*! + * Returns a reference to the frame list. This is an FrameList of all of + * the frames in the tag in the order that they were parsed. + * + * This can be useful if for example you want iterate over the tag's frames + * in the order that they occur in the tag. + * + * \warning You should not modify this data structure directly, instead + * use addFrame() and removeFrame(). + */ + const FrameList &frameList() const; + + /*! + * Returns the frame list for frames with the id \a frameID or an empty + * list if there are no frames of that type. This is just a convenience + * and is equivalent to: + * + * \code + * frameListMap()[frameID]; + * \endcode + * + * \see frameListMap() + */ + const FrameList &frameList(const ByteVector &frameID) const; + + /*! + * Add a frame to the tag. At this point the tag takes ownership of + * the frame and will handle freeing its memory. + * + * \note Using this method will invalidate any pointers on the list + * returned by frameList() + */ + void addFrame(Frame *frame); + + /*! + * Remove a frame from the tag. If \a del is true the frame's memory + * will be freed; if it is false, it must be deleted by the user. + * + * \note Using this method will invalidate any pointers on the list + * returned by frameList() + */ + void removeFrame(Frame *frame, bool del = true); + + /*! + * Remove all frames of type \a id from the tag and free their memory. + * + * \note Using this method will invalidate any pointers on the list + * returned by frameList() + */ + void removeFrames(const ByteVector &id); + + /*! + * Render the tag back to binary data, suitable to be written to disk. + */ + ByteVector render() const; + + protected: + /*! + * Reads data from the file specified in the constructor. It does basic + * parsing of the data in the largest chunks. It partitions the tag into + * the Header, the body of the tag (which contains the ExtendedHeader and + * frames) and Footer. + */ + void read(); + + /*! + * This is called by read to parse the body of the tag. It determines if an + * extended header exists and adds frames to the FrameListMap. + */ + void parse(const ByteVector &data); + + /*! + * Sets the value of the text frame with the Frame ID \a id to \a value. + * If the frame does not exist, it is created. + */ + void setTextFrame(const ByteVector &id, const String &value); + + private: + Tag(const Tag &); + Tag &operator=(const Tag &); + + class TagPrivate; + TagPrivate *d; + }; + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/mpegfile.cpp b/Libraries/TagLib/Files/taglib/mpeg/mpegfile.cpp new file mode 100644 index 000000000..56c1b4870 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/mpegfile.cpp @@ -0,0 +1,698 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "mpegfile.h" +#include "mpegheader.h" + +using namespace TagLib; + +namespace TagLib { + /*! + * A union of the ID3v2 and ID3v1 tags. + */ + class MPEGTag : public TagLib::Tag + { + public: + MPEGTag(MPEG::File *f) : TagLib::Tag(), file(f) {} + + virtual String title() const + { + if(file->ID3v2Tag() && !file->ID3v2Tag()->title().isEmpty()) + return file->ID3v2Tag()->title(); + + if(file->ID3v1Tag()) + return file->ID3v1Tag()->title(); + + return String::null; + } + + virtual String artist() const + { + if(file->ID3v2Tag() && !file->ID3v2Tag()->artist().isEmpty()) + return file->ID3v2Tag()->artist(); + + if(file->ID3v1Tag()) + return file->ID3v1Tag()->artist(); + + return String::null; + } + + virtual String album() const + { + if(file->ID3v2Tag() && !file->ID3v2Tag()->album().isEmpty()) + return file->ID3v2Tag()->album(); + + if(file->ID3v1Tag()) + return file->ID3v1Tag()->album(); + + return String::null; + } + + virtual String comment() const + { + if(file->ID3v2Tag() && !file->ID3v2Tag()->comment().isEmpty()) + return file->ID3v2Tag()->comment(); + + if(file->ID3v1Tag()) + return file->ID3v1Tag()->comment(); + + return String::null; + } + + virtual String genre() const + { + if(file->ID3v2Tag() && !file->ID3v2Tag()->genre().isEmpty()) + return file->ID3v2Tag()->genre(); + + if(file->ID3v1Tag()) + return file->ID3v1Tag()->genre(); + + return String::null; + } + + virtual uint year() const + { + if(file->ID3v2Tag() && file->ID3v2Tag()->year() > 0) + return file->ID3v2Tag()->year(); + + if(file->ID3v1Tag()) + return file->ID3v1Tag()->year(); + + return 0; + } + + virtual uint track() const + { + if(file->ID3v2Tag() && file->ID3v2Tag()->track() > 0) + return file->ID3v2Tag()->track(); + + if(file->ID3v1Tag()) + return file->ID3v1Tag()->track(); + + return 0; + } + + virtual void setTitle(const String &s) + { + file->ID3v2Tag(true)->setTitle(s); + file->ID3v1Tag(true)->setTitle(s); + } + + virtual void setArtist(const String &s) + { + file->ID3v2Tag(true)->setArtist(s); + file->ID3v1Tag(true)->setArtist(s); + } + + virtual void setAlbum(const String &s) + { + file->ID3v2Tag(true)->setAlbum(s); + file->ID3v1Tag(true)->setAlbum(s); + } + + virtual void setComment(const String &s) + { + file->ID3v2Tag(true)->setComment(s); + file->ID3v1Tag(true)->setComment(s); + } + + virtual void setGenre(const String &s) + { + file->ID3v2Tag(true)->setGenre(s); + file->ID3v1Tag(true)->setGenre(s); + } + + virtual void setYear(uint i) + { + file->ID3v2Tag(true)->setYear(i); + file->ID3v1Tag(true)->setYear(i); + } + + virtual void setTrack(uint i) + { + file->ID3v2Tag(true)->setTrack(i); + file->ID3v1Tag(true)->setTrack(i); + } + + private: + MPEG::File *file; + }; +} + +class MPEG::File::FilePrivate +{ +public: + FilePrivate(ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : + ID3v2FrameFactory(frameFactory), + ID3v2Tag(0), + ID3v2Location(-1), + ID3v2OriginalSize(0), + APETag(0), + APELocation(-1), + APEOriginalSize(0), + ID3v1Tag(0), + ID3v1Location(-1), + tag(0), + hasID3v2(false), + hasID3v1(false), + hasAPE(false), + properties(0) {} + + ~FilePrivate() { + delete ID3v2Tag; + delete ID3v1Tag; + delete tag; + delete properties; + } + + const ID3v2::FrameFactory *ID3v2FrameFactory; + ID3v2::Tag *ID3v2Tag; + long ID3v2Location; + uint ID3v2OriginalSize; + + APE::Tag *APETag; + long APELocation; + uint APEOriginalSize; + + ID3v1::Tag *ID3v1Tag; + long ID3v1Location; + + MPEGTag *tag; + + // These indicate whether the file *on disk* has these tags, not if + // this data structure does. This is used in computing offsets. + + bool hasID3v2; + bool hasID3v1; + bool hasAPE; + + Properties *properties; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MPEG::File::File(const char *file, bool readProperties, + Properties::ReadStyle propertiesStyle) : TagLib::File(file) +{ + d = new FilePrivate; + if(isOpen()) { + d->tag = new MPEGTag(this); + read(readProperties, propertiesStyle); + } +} + +MPEG::File::File(const char *file, ID3v2::FrameFactory *frameFactory, + bool readProperties, Properties::ReadStyle propertiesStyle) : + TagLib::File(file) +{ + d = new FilePrivate(frameFactory); + if(isOpen()) { + d->tag = new MPEGTag(this); + read(readProperties, propertiesStyle); + } +} + +MPEG::File::~File() +{ + delete d; +} + +TagLib::Tag *MPEG::File::tag() const +{ + return d->tag; +} + +MPEG::Properties *MPEG::File::audioProperties() const +{ + return d->properties; +} + +bool MPEG::File::save() +{ + return save(AllTags); +} + +bool MPEG::File::save(int tags) +{ + if(tags == NoTags) + return strip(AllTags); + + if(!d->ID3v2Tag && !d->ID3v1Tag && !d->APETag) { + + if(d->hasID3v1 || d->hasID3v2 || d->hasAPE) + return strip(AllTags); + + return true; + } + + if(readOnly()) { + debug("MPEG::File::save() -- File is read only."); + return false; + } + + // Create the tags if we've been asked to. Copy the values from the tag that + // does exist into the new tag. + + if((tags & ID3v2) && d->ID3v1Tag) + Tag::duplicate(d->ID3v1Tag, ID3v2Tag(true), false); + + if((tags & ID3v1) && d->ID3v2Tag) + Tag::duplicate(d->ID3v2Tag, ID3v1Tag(true), false); + + bool success = true; + + if(ID3v2 & tags) { + + if(d->ID3v2Tag && !d->ID3v2Tag->isEmpty()) { + + if(!d->hasID3v2) + d->ID3v2Location = 0; + + insert(d->ID3v2Tag->render(), d->ID3v2Location, d->ID3v2OriginalSize); + } + else + success = strip(ID3v2, false) && success; + } + else if(d->hasID3v2) + success = strip(ID3v2) && success; + + if(ID3v1 & tags) { + if(d->ID3v1Tag && !d->ID3v1Tag->isEmpty()) { + int offset = d->hasID3v1 ? -128 : 0; + seek(offset, End); + writeBlock(d->ID3v1Tag->render()); + } + else + success = strip(ID3v1) && success; + } + else if(d->hasID3v1) + success = strip(ID3v1, false) && success; + + // Dont save an APE-tag unless one has been created + if((APE & tags) && d->APETag) { + if(d->hasAPE) + insert(d->APETag->render(), d->APELocation, d->APEOriginalSize); + else { + if(d->hasID3v1) { + insert(d->APETag->render(), d->ID3v1Location, 0); + d->APEOriginalSize = d->APETag->footer()->completeTagSize(); + d->hasAPE = true; + d->APELocation = d->ID3v1Location; + d->ID3v1Location += d->APEOriginalSize; + } + else { + seek(0, End); + d->APELocation = tell(); + writeBlock(d->APETag->render()); + d->APEOriginalSize = d->APETag->footer()->completeTagSize(); + d->hasAPE = true; + } + } + } + else if(d->hasAPE) + success = strip(APE, false) && success; + + return success; +} + +ID3v2::Tag *MPEG::File::ID3v2Tag(bool create) +{ + if(!create || d->ID3v2Tag) + return d->ID3v2Tag; + + // no ID3v2 tag exists and we've been asked to create one + + d->ID3v2Tag = new ID3v2::Tag; + return d->ID3v2Tag; +} + +ID3v1::Tag *MPEG::File::ID3v1Tag(bool create) +{ + if(!create || d->ID3v1Tag) + return d->ID3v1Tag; + + // no ID3v1 tag exists and we've been asked to create one + + d->ID3v1Tag = new ID3v1::Tag; + return d->ID3v1Tag; +} + +APE::Tag *MPEG::File::APETag(bool create) +{ + if(!create || d->APETag) + return d->APETag; + + // no APE tag exists and we've been asked to create one + + d->APETag = new APE::Tag; + return d->APETag; +} + +bool MPEG::File::strip(int tags) +{ + return strip(tags, true); +} + +bool MPEG::File::strip(int tags, bool freeMemory) +{ + if(readOnly()) { + debug("MPEG::File::strip() - Cannot strip tags from a read only file."); + return false; + } + + if((tags & ID3v2) && d->hasID3v2) { + removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); + d->ID3v2Location = -1; + d->ID3v2OriginalSize = 0; + d->hasID3v2 = false; + if(freeMemory) { + delete d->ID3v2Tag; + d->ID3v2Tag = 0; + } + + // v1 tag location has changed, update if it exists + if(d->ID3v1Tag) + d->ID3v1Location = findID3v1(); + } + + if((tags & ID3v1) && d->hasID3v1) { + truncate(d->ID3v1Location); + d->ID3v1Location = -1; + d->hasID3v1 = false; + if(freeMemory) { + delete d->ID3v1Tag; + d->ID3v1Tag = 0; + } + } + + if((tags & APE) && d->hasAPE) { + removeBlock(d->APELocation, d->APEOriginalSize); + d->APELocation = -1; + d->hasAPE = false; + if(d->hasID3v1) { + if (d->ID3v1Location > d->APELocation) + d->ID3v1Location -= d->APEOriginalSize; + } + if(freeMemory) { + delete d->APETag; + d->APETag = 0; + } + } + + return true; +} + +void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) +{ + d->ID3v2FrameFactory = factory; +} + +long MPEG::File::nextFrameOffset(long position) +{ + // TODO: This will miss syncs spanning buffer read boundaries. + + ByteVector buffer = readBlock(bufferSize()); + + while(buffer.size() > 0) { + seek(position); + ByteVector buffer = readBlock(bufferSize()); + + for(uint i = 0; i < buffer.size(); i++) { + if(uchar(buffer[i]) == 0xff && secondSynchByte(buffer[i + 1])) + return position + i; + } + position += bufferSize(); + } + + return -1; +} + +long MPEG::File::previousFrameOffset(long position) +{ + // TODO: This will miss syncs spanning buffer read boundaries. + + while(int(position - bufferSize()) > int(bufferSize())) { + position -= bufferSize(); + seek(position); + ByteVector buffer = readBlock(bufferSize()); + + // If the amount of data is smaller than an MPEG header (4 bytes) there's no + // chance of this being valid. + + if(buffer.size() < 4) + return -1; + + for(int i = buffer.size() - 2; i >= 0; i--) { + if(uchar(buffer[i]) == 0xff && secondSynchByte(buffer[i + 1])) + return position + i; + } + } + + return -1; +} + +long MPEG::File::firstFrameOffset() +{ + long position = 0; + + if(d->ID3v2Tag) + position = d->ID3v2Location + d->ID3v2Tag->header()->completeTagSize(); + + return nextFrameOffset(position); +} + +long MPEG::File::lastFrameOffset() +{ + return previousFrameOffset(d->ID3v1Tag ? d->ID3v1Location - 1 : length()); +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void MPEG::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) +{ + // Look for an ID3v2 tag + + d->ID3v2Location = findID3v2(); + + if(d->ID3v2Location >= 0) { + + d->ID3v2Tag = new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory); + + d->ID3v2OriginalSize = d->ID3v2Tag->header()->completeTagSize(); + + if(d->ID3v2Tag->header()->tagSize() <= 0) { + delete d->ID3v2Tag; + d->ID3v2Tag = 0; + } + else + d->hasID3v2 = true; + } + + // Look for an ID3v1 tag + + d->ID3v1Location = findID3v1(); + + if(d->ID3v1Location >= 0) { + d->ID3v1Tag = new ID3v1::Tag(this, d->ID3v1Location); + d->hasID3v1 = true; + } + + // Look for an APE tag + + d->APELocation = findAPE(); + + if(d->APELocation >= 0) { + + d->APETag = new APE::Tag(this, d->APELocation); + + d->APEOriginalSize = d->APETag->footer()->completeTagSize(); + + d->APELocation = d->APELocation + d->APETag->footer()->size() - d->APEOriginalSize; + + d->hasAPE = true; + } + + if(readProperties) + d->properties = new Properties(this, propertiesStyle); +} + +long MPEG::File::findID3v2() +{ + // This method is based on the contents of TagLib::File::find(), but because + // of some subtlteies -- specifically the need to look for the bit pattern of + // an MPEG sync, it has been modified for use here. + + if(isValid() && ID3v2::Header::fileIdentifier().size() <= bufferSize()) { + + // The position in the file that the current buffer starts at. + + long bufferOffset = 0; + ByteVector buffer; + + // These variables are used to keep track of a partial match that happens at + // the end of a buffer. + + int previousPartialMatch = -1; + bool previousPartialSynchMatch = false; + + // Save the location of the current read pointer. We will restore the + // position using seek() before all returns. + + long originalPosition = tell(); + + // Start the search at the beginning of the file. + + seek(0); + + // This loop is the crux of the find method. There are three cases that we + // want to account for: + // (1) The previously searched buffer contained a partial match of the search + // pattern and we want to see if the next one starts with the remainder of + // that pattern. + // + // (2) The search pattern is wholly contained within the current buffer. + // + // (3) The current buffer ends with a partial match of the pattern. We will + // note this for use in the next itteration, where we will check for the rest + // of the pattern. + + for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { + + // (1) previous partial match + + if(previousPartialSynchMatch && secondSynchByte(buffer[0])) + return -1; + + if(previousPartialMatch >= 0 && int(bufferSize()) > previousPartialMatch) { + const int patternOffset = (bufferSize() - previousPartialMatch); + if(buffer.containsAt(ID3v2::Header::fileIdentifier(), 0, patternOffset)) { + seek(originalPosition); + return bufferOffset - bufferSize() + previousPartialMatch; + } + } + + // (2) pattern contained in current buffer + + long location = buffer.find(ID3v2::Header::fileIdentifier()); + if(location >= 0) { + seek(originalPosition); + return bufferOffset + location; + } + + int firstSynchByte = buffer.find(char(uchar(255))); + + // Here we have to loop because there could be several of the first + // (11111111) byte, and we want to check all such instances until we find + // a full match (11111111 111) or hit the end of the buffer. + + while(firstSynchByte >= 0) { + + // if this *is not* at the end of the buffer + + if(firstSynchByte < int(buffer.size()) - 1) { + if(secondSynchByte(buffer[firstSynchByte + 1])) { + // We've found the frame synch pattern. + seek(originalPosition); + return -1; + } + else { + + // We found 11111111 at the end of the current buffer indicating a + // partial match of the synch pattern. The find() below should + // return -1 and break out of the loop. + + previousPartialSynchMatch = true; + } + } + + // Check in the rest of the buffer. + + firstSynchByte = buffer.find(char(uchar(255)), firstSynchByte + 1); + } + + // (3) partial match + + previousPartialMatch = buffer.endsWithPartialMatch(ID3v2::Header::fileIdentifier()); + + bufferOffset += bufferSize(); + } + + // Since we hit the end of the file, reset the status before continuing. + + clear(); + + seek(originalPosition); + } + + return -1; +} + +long MPEG::File::findID3v1() +{ + if(isValid()) { + seek(-128, End); + long p = tell(); + + if(readBlock(3) == ID3v1::Tag::fileIdentifier()) + return p; + } + return -1; +} + +long MPEG::File::findAPE() +{ + if(isValid()) { + if (d->hasID3v1) + seek(-160, End); + else + seek(-32, End); + + long p = tell(); + + if(readBlock(8) == APE::Tag::fileIdentifier()) + return p; + } + return -1; +} + +bool MPEG::File::secondSynchByte(char byte) +{ + if(uchar(byte) == 0xff) + return false; + + std::bitset<8> b(byte); + + // check to see if the byte matches 111xxxxx + return b.test(7) && b.test(6) && b.test(5); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/mpegfile.h b/Libraries/TagLib/Files/taglib/mpeg/mpegfile.h new file mode 100644 index 000000000..431523e08 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/mpegfile.h @@ -0,0 +1,260 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_MPEGFILE_H +#define TAGLIB_MPEGFILE_H + +#include + +#include "mpegproperties.h" + +namespace TagLib { + + namespace ID3v2 { class Tag; class FrameFactory; } + namespace ID3v1 { class Tag; } + namespace APE { class Tag; } + + //! An implementation of TagLib::File with MPEG (MP3) specific methods + + namespace MPEG { + + //! An MPEG file class with some useful methods specific to MPEG + + /*! + * This implements the generic TagLib::File API and additionally provides + * access to properties that are distinct to MPEG files, notably access + * to the different ID3 tags. + */ + + class File : public TagLib::File + { + public: + /*! + * This set of flags is used for various operations and is suitable for + * being OR-ed together. + */ + enum TagTypes { + //! Empty set. Matches no tag types. + NoTags = 0x0000, + //! Matches ID3v1 tags. + ID3v1 = 0x0001, + //! Matches ID3v2 tags. + ID3v2 = 0x0002, + //! Matches APE tags. + APE = 0x0004, + //! Matches all tag types. + AllTags = 0xffff + }; + + /*! + * Contructs an MPEG file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + * + * \deprecated This constructor will be dropped in favor of the one below + * in a future version. + */ + File(const char *file, bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Contructs an MPEG file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. The frames will be created using + * \a frameFactory. + */ + // BIC: merge with the above constructor + File(const char *file, ID3v2::FrameFactory *frameFactory, + bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns a pointer to a tag that is the union of the ID3v2 and ID3v1 + * tags. The ID3v2 tag is given priority in reading the information -- if + * requested information exists in both the ID3v2 tag and the ID3v1 tag, + * the information from the ID3v2 tag will be returned. + * + * If you would like more granular control over the content of the tags, + * with the concession of generality, use the tag-type specific calls. + * + * \note As this tag is not implemented as an ID3v2 tag or an ID3v1 tag, + * but a union of the two this pointer may not be cast to the specific + * tag types. + * + * \see ID3v1Tag() + * \see ID3v2Tag() + * \see APETag() + */ + virtual Tag *tag() const; + + /*! + * Returns the MPEG::Properties for this file. If no audio properties + * were read then this will return a null pointer. + */ + virtual Properties *audioProperties() const; + + /*! + * Save the file. If at least one tag -- ID3v1 or ID3v2 -- exists this + * will duplicate its content into the other tag. This returns true + * if saving was successful. + * + * If neither exists or if both tags are empty, this will strip the tags + * from the file. + * + * This is the same as calling save(AllTags); + * + * If you would like more granular control over the content of the tags, + * with the concession of generality, use paramaterized save call below. + * + * \see save(int tags) + */ + virtual bool save(); + + /*! + * Save the file. This will attempt to save all of the tag types that are + * specified by OR-ing together TagTypes values. The save() method above + * uses AllTags. This returns true if saving was successful. + * + * This strips all tags not included in the mask, but does not modify them + * in memory, so later calls to save() which make use of these tags will + * remain valid. This also strips empty tags. + */ + bool save(int tags); + + /*! + * Returns a pointer to the ID3v2 tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid ID3v2 tag. If \a create is true it will create + * an ID3v2 tag if one does not exist. + * + * \note The Tag is still owned by the MPEG::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + ID3v2::Tag *ID3v2Tag(bool create = false); + + /*! + * Returns a pointer to the ID3v1 tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid ID3v1 tag. If \a create is true it will create + * an ID3v1 tag if one does not exist. + * + * \note The Tag is still owned by the MPEG::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + ID3v1::Tag *ID3v1Tag(bool create = false); + + /*! + * Returns a pointer to the APE tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid APE tag. If \a create is true it will create + * an APE tag if one does not exist. + * + * \note The Tag is still owned by the MPEG::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + APE::Tag *APETag(bool create = false); + + /*! + * This will strip the tags that match the OR-ed together TagTypes from the + * file. By default it strips all tags. It returns true if the tags are + * successfully stripped. + * + * This is equivalent to strip(tags, true) + * + * \note This will also invalidate pointers to the ID3 and APE tags + * as their memory will be freed. + */ + bool strip(int tags = AllTags); + + /*! + * This will strip the tags that match the OR-ed together TagTypes from the + * file. By default it strips all tags. It returns true if the tags are + * successfully stripped. + * + * If \a freeMemory is true the ID3 and APE tags will be deleted and + * pointers to them will be invalidated. + */ + // BIC: merge with the method above + bool strip(int tags, bool freeMemory); + + /*! + * Set the ID3v2::FrameFactory to something other than the default. + * + * \see ID3v2FrameFactory + */ + void setID3v2FrameFactory(const ID3v2::FrameFactory *factory); + + /*! + * Returns the position in the file of the first MPEG frame. + */ + long firstFrameOffset(); + + /*! + * Returns the position in the file of the next MPEG frame, + * using the current position as start + */ + long nextFrameOffset(long position); + + /*! + * Returns the position in the file of the previous MPEG frame, + * using the current position as start + */ + long previousFrameOffset(long position); + + /*! + * Returns the position in the file of the last MPEG frame. + */ + long lastFrameOffset(); + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + long findID3v2(); + long findID3v1(); + long findAPE(); + + /*! + * MPEG frames can be recognized by the bit pattern 11111111 111, so the + * first byte is easy to check for, however checking to see if the second byte + * starts with \e 111 is a bit more tricky, hence this member function. + */ + static bool secondSynchByte(char byte); + + class FilePrivate; + FilePrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/mpegheader.cpp b/Libraries/TagLib/Files/taglib/mpeg/mpegheader.cpp new file mode 100644 index 000000000..eb93db451 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/mpegheader.cpp @@ -0,0 +1,253 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include +#include +#include + +#include "mpegheader.h" + +using namespace TagLib; + +class MPEG::Header::HeaderPrivate : public RefCounter +{ +public: + HeaderPrivate() : + isValid(false), + version(Version1), + layer(0), + protectionEnabled(false), + sampleRate(0), + isPadded(false), + channelMode(Stereo), + isCopyrighted(false), + isOriginal(false), + frameLength(0) {} + + bool isValid; + Version version; + int layer; + bool protectionEnabled; + int bitrate; + int sampleRate; + bool isPadded; + ChannelMode channelMode; + bool isCopyrighted; + bool isOriginal; + int frameLength; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MPEG::Header::Header(const ByteVector &data) +{ + d = new HeaderPrivate; + parse(data); +} + +MPEG::Header::Header(const Header &h) : d(h.d) +{ + d->ref(); +} + +MPEG::Header::~Header() +{ + if (d->deref()) + delete d; +} + +bool MPEG::Header::isValid() const +{ + return d->isValid; +} + +MPEG::Header::Version MPEG::Header::version() const +{ + return d->version; +} + +int MPEG::Header::layer() const +{ + return d->layer; +} + +bool MPEG::Header::protectionEnabled() const +{ + return d->protectionEnabled; +} + +int MPEG::Header::bitrate() const +{ + return d->bitrate; +} + +int MPEG::Header::sampleRate() const +{ + return d->sampleRate; +} + +bool MPEG::Header::isPadded() const +{ + return d->isPadded; +} + +MPEG::Header::ChannelMode MPEG::Header::channelMode() const +{ + return d->channelMode; +} + +bool MPEG::Header::isCopyrighted() const +{ + return d->isCopyrighted; +} + +bool MPEG::Header::isOriginal() const +{ + return d->isOriginal; +} + +int MPEG::Header::frameLength() const +{ + return d->frameLength; +} + +MPEG::Header &MPEG::Header::operator=(const Header &h) +{ + if(&h == this) + return *this; + + if(d->deref()) + delete d; + + d = h.d; + d->ref(); + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void MPEG::Header::parse(const ByteVector &data) +{ + if(data.size() < 4 || uchar(data[0]) != 0xff) { + debug("MPEG::Header::parse() -- First byte did not mactch MPEG synch."); + return; + } + + std::bitset<32> flags(data.toUInt()); + + // Check for the second byte's part of the MPEG synch + + if(!flags[23] || !flags[22] || !flags[21]) { + debug("MPEG::Header::parse() -- Second byte did not mactch MPEG synch."); + return; + } + + // Set the MPEG version + + if(!flags[20] && !flags[19]) + d->version = Version2_5; + else if(flags[20] && !flags[19]) + d->version = Version2; + else if(flags[20] && flags[19]) + d->version = Version1; + + // Set the MPEG layer + + if(!flags[18] && flags[17]) + d->layer = 3; + else if(flags[18] && !flags[17]) + d->layer = 2; + else if(flags[18] && flags[17]) + d->layer = 1; + + d->protectionEnabled = !flags[16]; + + // Set the bitrate + + static const int bitrates[2][3][16] = { + { // Version 1 + { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1 + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // layer 2 + { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3 + }, + { // Version 2 or 2.5 + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } // layer 3 + } + }; + + const int versionIndex = d->version == Version1 ? 0 : 1; + const int layerIndex = d->layer > 0 ? d->layer - 1 : 0; + + // The bitrate index is encoded as the first 4 bits of the 3rd byte, + // i.e. 1111xxxx + + int i = uchar(data[2]) >> 4; + + d->bitrate = bitrates[versionIndex][layerIndex][i]; + + // Set the sample rate + + static const int sampleRates[3][4] = { + { 44100, 48000, 32000, 0 }, // Version 1 + { 22050, 24000, 16000, 0 }, // Version 2 + { 11025, 12000, 8000, 0 } // Version 2.5 + }; + + // The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx + + i = uchar(data[2]) >> 2 & 0x03; + + d->sampleRate = sampleRates[d->version][i]; + + if(d->sampleRate == 0) { + debug("MPEG::Header::parse() -- Invalid sample rate."); + return; + } + + // The channel mode is encoded as a 2 bit value at the end of the 3nd byte, + // i.e. xxxxxx11 + + d->channelMode = ChannelMode(uchar(data[2]) & 0x3); + + // TODO: Add mode extension for completeness + + d->isCopyrighted = flags[0]; + d->isOriginal = flags[1]; + + // Calculate the frame length + + if(d->layer == 1) + d->frameLength = 24000 * 2 * d->bitrate / d->sampleRate + int(d->isPadded); + else + d->frameLength = 72000 * d->bitrate / d->sampleRate + int(d->isPadded); + + // Now that we're done parsing, set this to be a valid frame. + + d->isValid = true; +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/mpegheader.h b/Libraries/TagLib/Files/taglib/mpeg/mpegheader.h new file mode 100644 index 000000000..40c3fda48 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/mpegheader.h @@ -0,0 +1,155 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_MPEGHEADER_H +#define TAGLIB_MPEGHEADER_H + +namespace TagLib { + + class ByteVector; + + namespace MPEG { + + //! An implementation of MP3 frame headers + + /*! + * This is an implementation of MPEG Layer III headers. The API follows more + * or less the binary format of these headers. I've used + * this + * document as a reference. + */ + + class Header + { + public: + /*! + * Parses an MPEG header based on \a data. + */ + Header(const ByteVector &data); + + /*! + * Does a shallow copy of \a h. + */ + Header(const Header &h); + + /*! + * Destroys this Header instance. + */ + virtual ~Header(); + + /*! + * Returns true if the frame is at least an appropriate size and has + * legal values. + */ + bool isValid() const; + + /*! + * The MPEG Version. + */ + enum Version { + //! MPEG Version 1 + Version1 = 0, + //! MPEG Version 2 + Version2 = 1, + //! MPEG Version 2.5 + Version2_5 = 2 + }; + + /*! + * Returns the MPEG Version of the header. + */ + Version version() const; + + /*! + * Returns the layer version. This will be between the values 1-3. + */ + int layer() const; + + /*! + * Returns true if the MPEG protection bit is enabled. + */ + bool protectionEnabled() const; + + /*! + * Returns the bitrate encoded in the header. + */ + int bitrate() const; + + /*! + * Returns the sample rate in Hz. + */ + int sampleRate() const; + + /*! + * Returns true if the frame is padded. + */ + bool isPadded() const; + + /*! + * There are a few combinations or one or two channel audio that are + * possible: + */ + enum ChannelMode { + //! Stereo + Stereo = 0, + //! Stereo + JointStereo = 1, + //! Dual Mono + DualChannel = 2, + //! Mono + SingleChannel = 3 + }; + + /*! + * Returns the channel mode for this frame. + */ + ChannelMode channelMode() const; + + /*! + * Returns true if the copyrighted bit is set. + */ + bool isCopyrighted() const; + + /*! + * Returns true if the "original" bit is set. + */ + bool isOriginal() const; + + /*! + * Returns the frame length. + */ + int frameLength() const; + + /*! + * Makes a shallow copy of the header. + */ + Header &operator=(const Header &h); + + private: + void parse(const ByteVector &data); + + class HeaderPrivate; + HeaderPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/mpegproperties.cpp b/Libraries/TagLib/Files/taglib/mpeg/mpegproperties.cpp new file mode 100644 index 000000000..ba245b206 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/mpegproperties.cpp @@ -0,0 +1,220 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "mpegproperties.h" +#include "mpegfile.h" +#include "xingheader.h" + +using namespace TagLib; + +class MPEG::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate(File *f, ReadStyle s) : + file(f), + style(s), + length(0), + bitrate(0), + sampleRate(0), + channels(0) {} + + File *file; + ReadStyle style; + int length; + int bitrate; + int sampleRate; + int channels; + Header::Version version; + int layer; + Header::ChannelMode channelMode; + bool isCopyrighted; + bool isOriginal; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MPEG::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) +{ + d = new PropertiesPrivate(file, style); + + if(file && file->isOpen()) + read(); +} + +MPEG::Properties::~Properties() +{ + delete d; +} + +int MPEG::Properties::length() const +{ + return d->length; +} + +int MPEG::Properties::bitrate() const +{ + return d->bitrate; +} + +int MPEG::Properties::sampleRate() const +{ + return d->sampleRate; +} + +int MPEG::Properties::channels() const +{ + return d->channels; +} + +MPEG::Header::Version MPEG::Properties::version() const +{ + return d->version; +} + +int MPEG::Properties::layer() const +{ + return d->layer; +} + +MPEG::Header::ChannelMode MPEG::Properties::channelMode() const +{ + return d->channelMode; +} + +bool MPEG::Properties::isCopyrighted() const +{ + return d->isCopyrighted; +} + +bool MPEG::Properties::isOriginal() const +{ + return d->isOriginal; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void MPEG::Properties::read() +{ + // Since we've likely just looked for the ID3v1 tag, start at the end of the + // file where we're least likely to have to have to move the disk head. + + long last = d->file->lastFrameOffset(); + + if(last < 0) { + debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream."); + return; + } + + d->file->seek(last); + Header lastHeader(d->file->readBlock(4)); + + long first = d->file->firstFrameOffset(); + + if(first < 0) { + debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream."); + return; + } + + if(!lastHeader.isValid()) { + + long pos = last; + + while(pos > first) { + + pos = d->file->previousFrameOffset(pos); + + if(pos < 0) + break; + + d->file->seek(pos); + Header header(d->file->readBlock(4)); + + if(header.isValid()) { + lastHeader = header; + last = pos; + break; + } + } + } + + // Now jump back to the front of the file and read what we need from there. + + d->file->seek(first); + Header firstHeader(d->file->readBlock(4)); + + if(!firstHeader.isValid() || !lastHeader.isValid()) { + debug("MPEG::Properties::read() -- Page headers were invalid."); + return; + } + + // Check for a Xing header that will help us in gathering information about a + // VBR stream. + + int xingHeaderOffset = MPEG::XingHeader::xingHeaderOffset(firstHeader.version(), + firstHeader.channelMode()); + + d->file->seek(first + xingHeaderOffset); + XingHeader xingHeader(d->file->readBlock(16)); + + // Read the length and the bitrate from the Xing header. + + if(xingHeader.isValid() && + firstHeader.sampleRate() > 0 && + xingHeader.totalFrames() > 0) + { + static const int blockSize[] = { 0, 384, 1152, 1152 }; + + double timePerFrame = blockSize[firstHeader.layer()]; + timePerFrame = firstHeader.sampleRate() > 0 ? timePerFrame / firstHeader.sampleRate() : 0; + d->length = int(timePerFrame * xingHeader.totalFrames()); + d->bitrate = d->length > 0 ? xingHeader.totalSize() * 8 / d->length / 1000 : 0; + } + + // Since there was no valid Xing header found, we hope that we're in a constant + // bitrate file. + + // TODO: Make this more robust with audio property detection for VBR without a + // Xing header. + + else if(firstHeader.frameLength() > 0 && firstHeader.bitrate() > 0) { + int frames = (last - first) / firstHeader.frameLength() + 1; + + d->length = int(float(firstHeader.frameLength() * frames) / + float(firstHeader.bitrate() * 125) + 0.5); + d->bitrate = firstHeader.bitrate(); + } + + + d->sampleRate = firstHeader.sampleRate(); + d->channels = firstHeader.channelMode() == Header::SingleChannel ? 1 : 2; + d->version = firstHeader.version(); + d->layer = firstHeader.layer(); + d->channelMode = firstHeader.channelMode(); + d->isCopyrighted = firstHeader.isCopyrighted(); + d->isOriginal = firstHeader.isOriginal(); +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/mpegproperties.h b/Libraries/TagLib/Files/taglib/mpeg/mpegproperties.h new file mode 100644 index 000000000..f50066cc0 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/mpegproperties.h @@ -0,0 +1,105 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_MPEGPROPERTIES_H +#define TAGLIB_MPEGPROPERTIES_H + +#include + +#include "mpegheader.h" + +namespace TagLib { + + namespace MPEG { + + class File; + + //! An implementation of audio property reading for MP3 + + /*! + * This reads the data from an MPEG Layer III stream found in the + * AudioProperties API. + */ + + class Properties : public AudioProperties + { + public: + /*! + * Create an instance of MPEG::Properties with the data read from the + * MPEG::File \a file. + */ + Properties(File *file, ReadStyle style = Average); + + /*! + * Destroys this MPEG Properties instance. + */ + virtual ~Properties(); + + // Reimplementations. + + virtual int length() const; + virtual int bitrate() const; + virtual int sampleRate() const; + virtual int channels() const; + + /*! + * Returns the MPEG Version of the file. + */ + Header::Version version() const; + + /*! + * Returns the layer version. This will be between the values 1-3. + */ + int layer() const; + + /*! + * Returns true if the MPEG protection bit is enabled. + */ + bool protectionEnabled() const; + + /*! + * Returns the channel mode for this frame. + */ + Header::ChannelMode channelMode() const; + + /*! + * Returns true if the copyrighted bit is set. + */ + bool isCopyrighted() const; + + /*! + * Returns true if the "original" bit is set. + */ + bool isOriginal() const; + + private: + Properties(const Properties &); + Properties &operator=(const Properties &); + + void read(); + + class PropertiesPrivate; + PropertiesPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/mpeg/xingheader.cpp b/Libraries/TagLib/Files/taglib/mpeg/xingheader.cpp new file mode 100644 index 000000000..5a0936355 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/xingheader.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + copyright : (C) 2003 by Ismael Orenstein + email : orenstein@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include + +#include "xingheader.h" + +using namespace TagLib; + +class MPEG::XingHeader::XingHeaderPrivate +{ +public: + XingHeaderPrivate() : + frames(0), + size(0), + valid(false) + {} + + uint frames; + uint size; + bool valid; +}; + +MPEG::XingHeader::XingHeader(const ByteVector &data) +{ + d = new XingHeaderPrivate; + parse(data); +} + +MPEG::XingHeader::~XingHeader() +{ + delete d; +} + +bool MPEG::XingHeader::isValid() const +{ + return d->valid; +} + +TagLib::uint MPEG::XingHeader::totalFrames() const +{ + return d->frames; +} + +TagLib::uint MPEG::XingHeader::totalSize() const +{ + return d->size; +} + +int MPEG::XingHeader::xingHeaderOffset(TagLib::MPEG::Header::Version v, + TagLib::MPEG::Header::ChannelMode c) +{ + if(v == MPEG::Header::Version1) { + if(c == MPEG::Header::SingleChannel) + return 0x15; + else + return 0x24; + } + else { + if(c == MPEG::Header::SingleChannel) + return 0x0D; + else + return 0x15; + } +} + +void MPEG::XingHeader::parse(const ByteVector &data) +{ + // Check to see if a valid Xing header is available. + + if(data.mid(0, 4) != "Xing") + return; + + // If the XingHeader doesn't contain the number of frames and the total stream + // info it's invalid. + + if(!(data[7] & 0x02)) { + debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total number of frames."); + return; + } + + if(!(data[7] & 0x04)) { + debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total stream size."); + return; + } + + d->frames = data.mid(8, 4).toUInt(); + d->size = data.mid(12, 4).toUInt(); + + d->valid = true; +} diff --git a/Libraries/TagLib/Files/taglib/mpeg/xingheader.h b/Libraries/TagLib/Files/taglib/mpeg/xingheader.h new file mode 100644 index 000000000..09e4bf91f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/mpeg/xingheader.h @@ -0,0 +1,91 @@ +/*************************************************************************** + copyright : (C) 2003 by Ismael Orenstein + email : orenstein@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_XINGHEADER_H +#define TAGLIB_XINGHEADER_H + +#include "mpegheader.h" + +namespace TagLib { + + class ByteVector; + + namespace MPEG { + + //! An implementation of the Xing VBR headers + + /*! + * This is a minimalistic implementation of the Xing VBR headers. Xing + * headers are often added to VBR (variable bit rate) MP3 streams to make it + * easy to compute the length and quality of a VBR stream. Our implementation + * is only concerned with the total size of the stream (so that we can + * calculate the total playing time and the average bitrate). It uses + * this text + * and the XMMS sources as references. + */ + + class XingHeader + { + public: + /*! + * Parses a Xing header based on \a data. The data must be at least 16 + * bytes long (anything longer than this is discarded). + */ + XingHeader(const ByteVector &data); + + /*! + * Destroy this XingHeader instance. + */ + virtual ~XingHeader(); + + /*! + * Returns true if the data was parsed properly and if there is a vaild + * Xing header present. + */ + bool isValid() const; + + /*! + * Returns the total number of frames. + */ + uint totalFrames() const; + + /*! + * Returns the total size of stream in bytes. + */ + uint totalSize() const; + + /*! + * Returns the offset for the start of this Xing header, given the + * version and channels of the frame + */ + static int xingHeaderOffset(TagLib::MPEG::Header::Version v, + TagLib::MPEG::Header::ChannelMode c); + + private: + void parse(const ByteVector &data); + + class XingHeaderPrivate; + XingHeaderPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/ogg/Makefile.am b/Libraries/TagLib/Files/taglib/ogg/Makefile.am new file mode 100644 index 000000000..d80e5e4fe --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/Makefile.am @@ -0,0 +1,23 @@ +SUBDIRS = vorbis flac + +INCLUDES = -I$(top_srcdir)/taglib -I$(top_srcdir)/taglib/toolkit $(all_includes) + +noinst_LTLIBRARIES = libogg.la + +libogg_la_SOURCES = \ + oggfile.cpp \ + oggpage.cpp \ + oggpageheader.cpp \ + xiphcomment.cpp + +taglib_include_HEADERS = \ + oggfile.h \ + oggpage.h \ + oggpageheader.h \ + xiphcomment.h + +taglib_includedir = $(includedir)/taglib + +libogg_la_LIBADD = ./vorbis/libvorbis.la ./flac/liboggflac.la + +EXTRA_DIST = $(libogg_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/ogg/Makefile.in b/Libraries/TagLib/Files/taglib/ogg/Makefile.in new file mode 100644 index 000000000..7f4b0d422 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/Makefile.in @@ -0,0 +1,664 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +SUBDIRS = vorbis flac + +INCLUDES = -I$(top_srcdir)/taglib -I$(top_srcdir)/taglib/toolkit $(all_includes) + +noinst_LTLIBRARIES = libogg.la + +libogg_la_SOURCES = \ + oggfile.cpp \ + oggpage.cpp \ + oggpageheader.cpp \ + xiphcomment.cpp + + +taglib_include_HEADERS = \ + oggfile.h \ + oggpage.h \ + oggpageheader.h \ + xiphcomment.h + + +taglib_includedir = $(includedir)/taglib + +libogg_la_LIBADD = ./vorbis/libvorbis.la ./flac/liboggflac.la + +EXTRA_DIST = $(libogg_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/ogg +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libogg_la_LDFLAGS = +libogg_la_DEPENDENCIES = ./vorbis/libvorbis.la ./flac/liboggflac.la +am_libogg_la_OBJECTS = oggfile.lo oggpage.lo oggpageheader.lo \ + xiphcomment.lo +#>- libogg_la_OBJECTS = $(am_libogg_la_OBJECTS) +#>+ 5 +libogg_la_final_OBJECTS = libogg_la.all_cpp.lo +libogg_la_nofinal_OBJECTS = oggfile.lo oggpage.lo oggpageheader.lo \ + xiphcomment.lo +@KDE_USE_FINAL_FALSE@libogg_la_OBJECTS = $(libogg_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libogg_la_OBJECTS = $(libogg_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/oggfile.Plo ./$(DEPDIR)/oggpage.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/oggpageheader.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/xiphcomment.Plo +#>+ 7 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libogg_la.all_cpp.P ./$(DEPDIR)/oggfile.Plo ./$(DEPDIR)/oggpage.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/oggpageheader.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/xiphcomment.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/oggfile.Plo ./$(DEPDIR)/oggpage.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/oggpageheader.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/xiphcomment.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libogg_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + + +RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ + ps-recursive install-info-recursive uninstall-info-recursive \ + all-recursive install-data-recursive install-exec-recursive \ + installdirs-recursive install-recursive uninstall-recursive \ + check-recursive installcheck-recursive +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +DIST_SUBDIRS = $(SUBDIRS) +SOURCES = $(libogg_la_SOURCES) + +#>- all: all-recursive +#>+ 1 +all: docs-am all-recursive + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/ogg/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ogg/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ogg/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libogg.la: $(libogg_la_OBJECTS) $(libogg_la_DEPENDENCIES) + $(CXXLINK) $(libogg_la_LDFLAGS) $(libogg_la_OBJECTS) $(libogg_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oggfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oggpage.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oggpageheader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xiphcomment.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + 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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: ctags-recursive $(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 +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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-recursive +#>+ 1 +clean: kde-rpo-clean clean-recursive + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-taglib_includeHEADERS + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-recursive distclean-tags distdir \ + dvi dvi-am dvi-recursive info info-am info-recursive install \ + install-am install-data install-data-am install-data-recursive \ + install-exec install-exec-am install-exec-recursive \ + install-info install-info-am install-info-recursive install-man \ + install-recursive install-strip install-taglib_includeHEADERS \ + installcheck installcheck-am installdirs installdirs-am \ + installdirs-recursive maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ + pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ + tags-recursive uninstall uninstall-am uninstall-info-am \ + uninstall-info-recursive uninstall-recursive \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ogg/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ogg/Makefile.in + + +#>+ 11 +libogg_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/oggfile.cpp $(srcdir)/oggpage.cpp $(srcdir)/oggpageheader.cpp $(srcdir)/xiphcomment.cpp + @echo 'creating libogg_la.all_cpp.cpp ...'; \ + rm -f libogg_la.all_cpp.files libogg_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libogg_la.all_cpp.final; \ + for file in oggfile.cpp oggpage.cpp oggpageheader.cpp xiphcomment.cpp ; do \ + echo "#include \"$$file\"" >> libogg_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libogg_la.all_cpp.final; \ + done; \ + cat libogg_la.all_cpp.final libogg_la.all_cpp.files > libogg_la.all_cpp.cpp; \ + rm -f libogg_la.all_cpp.final libogg_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libogg_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libogg_la_OBJECTS="$(libogg_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libogg_la_OBJECTS="$(libogg_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libogg_la_OBJECTS="$(libogg_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libogg_la_OBJECTS="$(libogg_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/ogg/flac/Makefile.am b/Libraries/TagLib/Files/taglib/ogg/flac/Makefile.am new file mode 100644 index 000000000..83c08539f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/flac/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ogg \ + -I$(top_srcdir)/taglib/flac \ + $(all_includes) + +noinst_LTLIBRARIES = liboggflac.la + +liboggflac_la_SOURCES = oggflacfile.cpp + +taglib_include_HEADERS = oggflacfile.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(liboggflac_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/ogg/flac/Makefile.in b/Libraries/TagLib/Files/taglib/ogg/flac/Makefile.in new file mode 100644 index 000000000..f882d772a --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/flac/Makefile.in @@ -0,0 +1,522 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ogg \ + -I$(top_srcdir)/taglib/flac \ + $(all_includes) + + +noinst_LTLIBRARIES = liboggflac.la + +liboggflac_la_SOURCES = oggflacfile.cpp + +taglib_include_HEADERS = oggflacfile.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(liboggflac_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/ogg/flac +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +liboggflac_la_LDFLAGS = +liboggflac_la_LIBADD = +am_liboggflac_la_OBJECTS = oggflacfile.lo +#>- liboggflac_la_OBJECTS = $(am_liboggflac_la_OBJECTS) +#>+ 1 +liboggflac_la_OBJECTS = oggflacfile.lo + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/oggflacfile.Plo +#>+ 2 +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/oggflacfile.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(liboggflac_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(liboggflac_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/ogg/flac/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ogg/flac/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ogg/flac/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +liboggflac.la: $(liboggflac_la_OBJECTS) $(liboggflac_la_DEPENDENCIES) + $(CXXLINK) $(liboggflac_la_LDFLAGS) $(liboggflac_la_OBJECTS) $(liboggflac_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oggflacfile.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ogg/flac/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ogg/flac/Makefile.in + + +#>+ 2 +final: + $(MAKE) all-am +#>+ 2 +final-install: + $(MAKE) install-am +#>+ 2 +no-final: + $(MAKE) all-am +#>+ 2 +no-final-install: + $(MAKE) install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/ogg/flac/oggflacfile.cpp b/Libraries/TagLib/Files/taglib/ogg/flac/oggflacfile.cpp new file mode 100644 index 000000000..9f8fd7cf8 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/flac/oggflacfile.cpp @@ -0,0 +1,245 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include + +#include +#include "oggflacfile.h" + +using namespace TagLib; +using TagLib::FLAC::Properties; + +class Ogg::FLAC::File::FilePrivate +{ +public: + FilePrivate() : + comment(0), + properties(0), + streamStart(0), + streamLength(0), + scanned(false), + hasXiphComment(false), + commentPacket(0) {} + + ~FilePrivate() + { + delete comment; + delete properties; + } + + Ogg::XiphComment *comment; + + Properties *properties; + ByteVector streamInfoData; + ByteVector xiphCommentData; + long streamStart; + long streamLength; + bool scanned; + + bool hasXiphComment; + int commentPacket; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::FLAC::File::File(const char *file, bool readProperties, + Properties::ReadStyle propertiesStyle) : Ogg::File(file) +{ + d = new FilePrivate; + read(readProperties, propertiesStyle); +} + +Ogg::FLAC::File::~File() +{ + delete d; +} + +Ogg::XiphComment *Ogg::FLAC::File::tag() const +{ + return d->comment; +} + +Properties *Ogg::FLAC::File::audioProperties() const +{ + return d->properties; +} + + +bool Ogg::FLAC::File::save() +{ + d->xiphCommentData = d->comment->render(); + + // Create FLAC metadata-block: + + // Put the size in the first 32 bit (I assume no more than 24 bit are used) + + ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size()); + + // Set the type of the metadata-block to be a Xiph / Vorbis comment + + v[0] = 4; + + // Append the comment-data after the 32 bit header + + v.append(d->xiphCommentData); + + // Save the packet at the old spot + // FIXME: Use padding if size is increasing + + setPacket(d->commentPacket, v); + + return Ogg::File::save(); +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void Ogg::FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) +{ + // Sanity: Check if we really have an Ogg/FLAC file + +/* + ByteVector oggHeader = packet(0); + + if (oggHeader.mid(28,4) != "fLaC") { + debug("Ogg::FLAC::File::read() -- Not an Ogg/FLAC file"); + setValid(false); + return; + }*/ + + // Look for FLAC metadata, including vorbis comments + + scan(); + + if (!d->scanned) { + setValid(false); + return; + } + + + if(d->hasXiphComment) + d->comment = new Ogg::XiphComment(xiphCommentData()); + else + d->comment = new Ogg::XiphComment; + + + if(readProperties) + d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle); +} + +ByteVector Ogg::FLAC::File::streamInfoData() +{ + scan(); + return d->streamInfoData; +} + +ByteVector Ogg::FLAC::File::xiphCommentData() +{ + scan(); + return d->xiphCommentData; +} + +long Ogg::FLAC::File::streamLength() +{ + scan(); + return d->streamLength; +} + +void Ogg::FLAC::File::scan() +{ + // Scan the metadata pages + + if(d->scanned) + return; + + if(!isValid()) + return; + + int ipacket = 1; + long overhead = 0; + + ByteVector metadataHeader = packet(ipacket); + + if(metadataHeader.isNull()) + return; + + ByteVector header = metadataHeader.mid(0,4); + + // Header format (from spec): + // <1> Last-metadata-block flag + // <7> BLOCK_TYPE + // 0 : STREAMINFO + // 1 : PADDING + // .. + // 4 : VORBIS_COMMENT + // .. + // <24> Length of metadata to follow + + char blockType = header[0] & 0x7f; + bool lastBlock = header[0] & 0x80; + uint length = header.mid(1, 3).toUInt(); + overhead += length; + + // Sanity: First block should be the stream_info metadata + + if(blockType != 0) { + debug("Ogg::FLAC::File::scan() -- Invalid Ogg/FLAC stream"); + return; + } + + d->streamInfoData = metadataHeader.mid(4,length); + + // Search through the remaining metadata + + while(!lastBlock) { + metadataHeader = packet(++ipacket); + + header = metadataHeader.mid(0, 4); + blockType = header[0] & 0x7f; + lastBlock = header[0] & 0x80; + length = header.mid(1, 3).toUInt(); + overhead += length; + + if(blockType == 1) { + // debug("Ogg::FLAC::File::scan() -- Padding found"); + } + else if(blockType == 4) { + // debug("Ogg::FLAC::File::scan() -- Vorbis-comments found"); + d->xiphCommentData = metadataHeader.mid(4, length); + d->hasXiphComment = true; + d->commentPacket = ipacket; + } + else if(blockType > 5) + debug("Ogg::FLAC::File::scan() -- Unknown metadata block"); + + } + + // End of metadata, now comes the datastream + d->streamStart = overhead; + d->streamLength = File::length() - d->streamStart; + + d->scanned = true; +} diff --git a/Libraries/TagLib/Files/taglib/ogg/flac/oggflacfile.h b/Libraries/TagLib/Files/taglib/ogg/flac/oggflacfile.h new file mode 100644 index 000000000..94ec57509 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/flac/oggflacfile.h @@ -0,0 +1,113 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_OGGFLACFILE_H +#define TAGLIB_OGGFLACFILE_H + +#include +#include + +#include + +namespace TagLib { + + class Tag; + + namespace Ogg { + + //! An implementation of Ogg FLAC metadata + + /*! + * This is implementation of FLAC metadata for Ogg FLAC files. For "pure" + * FLAC files look under the FLAC hiearchy. + * + * Unlike "pure" FLAC-files, Ogg FLAC only supports Xiph-comments, + * while the audio-properties are the same. + */ + namespace FLAC { + + using TagLib::FLAC::Properties; + + //! An implementation of TagLib::File with Ogg/FLAC specific methods + + /*! + * This implements and provides an interface for Ogg/FLAC files to the + * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing + * the abstract TagLib::File API as well as providing some additional + * information specific to Ogg FLAC files. + */ + + class File : public Ogg::File + { + public: + /*! + * Contructs an Ogg/FLAC file from \a file. If \a readProperties is true + * the file's audio properties will also be read using \a propertiesStyle. + * If false, \a propertiesStyle is ignored. + */ + File(const char *file, bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns the Tag for this file. This will always be a XiphComment. + */ + virtual XiphComment *tag() const; + + /*! + * Returns the FLAC::Properties for this file. If no audio properties + * were read then this will return a null pointer. + */ + virtual Properties *audioProperties() const; + + /*! + * Save the file. This will primarily save and update the XiphComment. + * Returns true if the save is successful. + */ + virtual bool save(); + + /*! + * Returns the length of the audio-stream, used by FLAC::Properties for + * calculating the bitrate. + */ + long streamLength(); + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + void scan(); + ByteVector streamInfoData(); + ByteVector xiphCommentData(); + + class FilePrivate; + FilePrivate *d; + }; + } // namespace FLAC + } // namespace Ogg +} // namespace TagLib + +#endif diff --git a/Libraries/TagLib/Files/taglib/ogg/oggfile.cpp b/Libraries/TagLib/Files/taglib/ogg/oggfile.cpp new file mode 100644 index 000000000..357a30edd --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/oggfile.cpp @@ -0,0 +1,332 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "oggfile.h" +#include "oggpage.h" +#include "oggpageheader.h" + +using namespace TagLib; + +class Ogg::File::FilePrivate +{ +public: + FilePrivate() : + streamSerialNumber(0), + firstPageHeader(0), + lastPageHeader(0), + currentPage(0), + currentPacketPage(0) + { + pages.setAutoDelete(true); + } + + ~FilePrivate() + { + delete firstPageHeader; + delete lastPageHeader; + } + + uint streamSerialNumber; + List pages; + PageHeader *firstPageHeader; + PageHeader *lastPageHeader; + std::vector< List > packetToPageMap; + Map dirtyPackets; + List dirtyPages; + + //! The current page for the reader -- used by nextPage() + Page *currentPage; + //! The current page for the packet parser -- used by packet() + Page *currentPacketPage; + //! The packets for the currentPacketPage -- used by packet() + ByteVectorList currentPackets; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::File::~File() +{ + delete d; +} + +ByteVector Ogg::File::packet(uint i) +{ + // Check to see if we're called setPacket() for this packet since the last + // save: + + if(d->dirtyPackets.contains(i)) + return d->dirtyPackets[i]; + + // If we haven't indexed the page where the packet we're interested in starts, + // begin reading pages until we have. + + while(d->packetToPageMap.size() <= i) { + if(!nextPage()) { + debug("Ogg::File::packet() -- Could not find the requested packet."); + return ByteVector::null; + } + } + + // Start reading at the first page that contains part (or all) of this packet. + // If the last read stopped at the packet that we're interested in, don't + // reread its packet list. (This should make sequential packet reads fast.) + + uint pageIndex = d->packetToPageMap[i].front(); + if(d->currentPacketPage != d->pages[pageIndex]) { + d->currentPacketPage = d->pages[pageIndex]; + d->currentPackets = d->currentPacketPage->packets(); + } + + // If the packet is completely contained in the first page that it's in, then + // just return it now. + + if(d->currentPacketPage->containsPacket(i) & Page::CompletePacket) + return d->currentPackets[i - d->currentPacketPage->firstPacketIndex()]; + + // If the packet is *not* completely contained in the first page that it's a + // part of then that packet trails off the end of the page. Continue appending + // the pages' packet data until we hit a page that either does not end with the + // packet that we're fetching or where the last packet is complete. + + ByteVector packet = d->currentPackets.back(); + while(d->currentPacketPage->containsPacket(i) & Page::EndsWithPacket && + !d->currentPacketPage->header()->lastPacketCompleted()) + { + pageIndex++; + if(pageIndex == d->pages.size()) { + if(!nextPage()) { + debug("Ogg::File::packet() -- Could not find the requested packet."); + return ByteVector::null; + } + } + d->currentPacketPage = d->pages[pageIndex]; + d->currentPackets = d->currentPacketPage->packets(); + packet.append(d->currentPackets.front()); + } + + return packet; +} + +void Ogg::File::setPacket(uint i, const ByteVector &p) +{ + while(d->packetToPageMap.size() <= i) { + if(!nextPage()) { + debug("Ogg::File::setPacket() -- Could not set the requested packet."); + return; + } + } + + List::ConstIterator it = d->packetToPageMap[i].begin(); + for(; it != d->packetToPageMap[i].end(); ++it) + d->dirtyPages.sortedInsert(*it, true); + + d->dirtyPackets.insert(i, p); +} + +const Ogg::PageHeader *Ogg::File::firstPageHeader() +{ + if(d->firstPageHeader) + return d->firstPageHeader->isValid() ? d->firstPageHeader : 0; + + long firstPageHeaderOffset = find("OggS"); + + if(firstPageHeaderOffset < 0) + return 0; + + d->firstPageHeader = new PageHeader(this, firstPageHeaderOffset); + return d->firstPageHeader->isValid() ? d->firstPageHeader : 0; +} + +const Ogg::PageHeader *Ogg::File::lastPageHeader() +{ + if(d->lastPageHeader) + return d->lastPageHeader->isValid() ? d->lastPageHeader : 0; + + long lastPageHeaderOffset = rfind("OggS"); + + if(lastPageHeaderOffset < 0) + return 0; + + d->lastPageHeader = new PageHeader(this, lastPageHeaderOffset); + return d->lastPageHeader->isValid() ? d->lastPageHeader : 0; +} + +bool Ogg::File::save() +{ + if(readOnly()) { + debug("Ogg::File::save() - Cannot save to a read only file."); + return false; + } + + List pageGroup; + + for(List::ConstIterator it = d->dirtyPages.begin(); it != d->dirtyPages.end(); ++it) { + if(!pageGroup.isEmpty() && pageGroup.back() + 1 != *it) { + writePageGroup(pageGroup); + pageGroup.clear(); + } + else + pageGroup.append(*it); + } + writePageGroup(pageGroup); + d->dirtyPages.clear(); + d->dirtyPackets.clear(); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::File::File(const char *file) : TagLib::File(file) +{ + d = new FilePrivate; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +bool Ogg::File::nextPage() +{ + long nextPageOffset; + int currentPacket; + + if(d->pages.isEmpty()) { + currentPacket = 0; + nextPageOffset = find("OggS"); + if(nextPageOffset < 0) + return false; + } + else { + if(d->currentPage->header()->lastPageOfStream()) + return false; + + if(d->currentPage->header()->lastPacketCompleted()) + currentPacket = d->currentPage->firstPacketIndex() + d->currentPage->packetCount(); + else + currentPacket = d->currentPage->firstPacketIndex() + d->currentPage->packetCount() - 1; + + nextPageOffset = d->currentPage->fileOffset() + d->currentPage->size(); + } + + // Read the next page and add it to the page list. + + d->currentPage = new Page(this, nextPageOffset); + + if(!d->currentPage->header()->isValid()) { + delete d->currentPage; + d->currentPage = 0; + return false; + } + + d->currentPage->setFirstPacketIndex(currentPacket); + + if(d->pages.isEmpty()) + d->streamSerialNumber = d->currentPage->header()->streamSerialNumber(); + + d->pages.append(d->currentPage); + + // Loop through the packets in the page that we just read appending the + // current page number to the packet to page map for each packet. + + for(uint i = 0; i < d->currentPage->packetCount(); i++) { + uint currentPacket = d->currentPage->firstPacketIndex() + i; + if(d->packetToPageMap.size() <= currentPacket) + d->packetToPageMap.push_back(List()); + d->packetToPageMap[currentPacket].append(d->pages.size() - 1); + } + + return true; +} + +void Ogg::File::writePageGroup(const List &pageGroup) +{ + if(pageGroup.isEmpty()) + return; + + ByteVectorList packets; + + // If the first page of the group isn't dirty, append its partial content here. + + if(!d->dirtyPages.contains(d->pages[pageGroup.front()]->firstPacketIndex())) + packets.append(d->pages[pageGroup.front()]->packets().front()); + + int previousPacket = -1; + int originalSize = 0; + + for(List::ConstIterator it = pageGroup.begin(); it != pageGroup.end(); ++it) { + uint firstPacket = d->pages[*it]->firstPacketIndex(); + uint lastPacket = firstPacket + d->pages[*it]->packetCount() - 1; + + List::ConstIterator last = --pageGroup.end(); + + for(uint i = firstPacket; i <= lastPacket; i++) { + + if(it == last && i == lastPacket && !d->dirtyPages.contains(i)) + packets.append(d->pages[*it]->packets().back()); + else if(int(i) != previousPacket) { + previousPacket = i; + packets.append(packet(i)); + } + } + originalSize += d->pages[*it]->size(); + } + + const bool continued = d->pages[pageGroup.front()]->header()->firstPacketContinued(); + const bool completed = d->pages[pageGroup.back()]->header()->lastPacketCompleted(); + + // TODO: This pagination method isn't accurate for what's being done here. + // This should account for real possibilities like non-aligned packets and such. + + List pages = Page::paginate(packets, Page::SinglePagePerGroup, + d->streamSerialNumber, pageGroup.front(), + continued, completed); + + ByteVector data; + for(List::ConstIterator it = pages.begin(); it != pages.end(); ++it) + data.append((*it)->render()); + + // The insertion algorithms could also be improve to queue and prioritize data + // on the way out. Currently it requires rewriting the file for every page + // group rather than just once; however, for tagging applications there will + // generally only be one page group, so it's not worth the time for the + // optimization at the moment. + + insert(data, d->pages[pageGroup.front()]->fileOffset(), originalSize); + + // Update the page index to include the pages we just created and to delete the + // old pages. + + for(List::ConstIterator it = pages.begin(); it != pages.end(); ++it) { + const int index = (*it)->header()->pageSequenceNumber(); + delete d->pages[index]; + d->pages[index] = *it; + } +} diff --git a/Libraries/TagLib/Files/taglib/ogg/oggfile.h b/Libraries/TagLib/Files/taglib/ogg/oggfile.h new file mode 100644 index 000000000..0ca59dd99 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/oggfile.h @@ -0,0 +1,107 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#ifndef TAGLIB_OGGFILE_H +#define TAGLIB_OGGFILE_H + +namespace TagLib { + + //! A namespace for the classes used by Ogg-based metadata files + + namespace Ogg { + + class PageHeader; + + //! An implementation of TagLib::File with some helpers for Ogg based formats + + /*! + * This is an implementation of Ogg file page and packet rendering and is of + * use to Ogg based formats. While the API is small this handles the + * non-trivial details of breaking up an Ogg stream into packets and makes + * these available (via subclassing) to the codec meta data implementations. + */ + + class File : public TagLib::File + { + public: + virtual ~File(); + + /*! + * Returns the packet contents for the i-th packet (starting from zero) + * in the Ogg bitstream. + * + * \warning The requires reading at least the packet header for every page + * up to the requested page. + */ + ByteVector packet(uint i); + + /*! + * Sets the packet with index \a i to the value \a p. + */ + void setPacket(uint i, const ByteVector &p); + + /*! + * Returns a pointer to the PageHeader for the first page in the stream or + * null if the page could not be found. + */ + const PageHeader *firstPageHeader(); + + /*! + * Returns a pointer to the PageHeader for the last page in the stream or + * null if the page could not be found. + */ + const PageHeader *lastPageHeader(); + + virtual bool save(); + + protected: + /*! + * Contructs an Ogg file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + * + * \note This constructor is protected since Ogg::File shouldn't be + * instantiated directly but rather should be used through the codec + * specific subclasses. + */ + File(const char *file); + + private: + File(const File &); + File &operator=(const File &); + + /*! + * Reads the next page and updates the internal "current page" pointer. + */ + bool nextPage(); + void writePageGroup(const List &group); + + class FilePrivate; + FilePrivate *d; + }; + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/ogg/oggpage.cpp b/Libraries/TagLib/Files/taglib/ogg/oggpage.cpp new file mode 100644 index 000000000..4387905e2 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/oggpage.cpp @@ -0,0 +1,251 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include "oggpage.h" +#include "oggpageheader.h" +#include "oggfile.h" + +using namespace TagLib; + +class Ogg::Page::PagePrivate +{ +public: + PagePrivate(File *f = 0, long pageOffset = -1) : + file(f), + fileOffset(pageOffset), + packetOffset(0), + header(f, pageOffset), + firstPacketIndex(-1) + { + if(file) { + packetOffset = fileOffset + header.size(); + packetSizes = header.packetSizes(); + dataSize = header.dataSize(); + } + } + + File *file; + long fileOffset; + long packetOffset; + int dataSize; + List packetSizes; + PageHeader header; + int firstPacketIndex; + ByteVectorList packets; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::Page::Page(Ogg::File *file, long pageOffset) +{ + d = new PagePrivate(file, pageOffset); +} + +Ogg::Page::~Page() +{ + delete d; +} + +long Ogg::Page::fileOffset() const +{ + return d->fileOffset; +} + +const Ogg::PageHeader *Ogg::Page::header() const +{ + return &d->header; +} + +int Ogg::Page::firstPacketIndex() const +{ + return d->firstPacketIndex; +} + +void Ogg::Page::setFirstPacketIndex(int index) +{ + d->firstPacketIndex = index; +} + +Ogg::Page::ContainsPacketFlags Ogg::Page::containsPacket(int index) const +{ + int lastPacketIndex = d->firstPacketIndex + packetCount() - 1; + if(index < d->firstPacketIndex || index > lastPacketIndex) + return DoesNotContainPacket; + + ContainsPacketFlags flags = DoesNotContainPacket; + + if(index == d->firstPacketIndex) + flags = ContainsPacketFlags(flags | BeginsWithPacket); + + if(index == lastPacketIndex) + flags = ContainsPacketFlags(flags | EndsWithPacket); + + // If there's only one page and it's complete: + + if(packetCount() == 1 && + !d->header.firstPacketContinued() && + d->header.lastPacketCompleted()) + { + flags = ContainsPacketFlags(flags | CompletePacket); + } + + // Or if the page is (a) the first page and it's complete or (b) the last page + // and it's complete or (c) a page in the middle. + + else if((flags & BeginsWithPacket && !d->header.firstPacketContinued()) || + (flags & EndsWithPacket && d->header.lastPacketCompleted()) || + (!(flags & BeginsWithPacket) && !(flags & EndsWithPacket))) + { + flags = ContainsPacketFlags(flags | CompletePacket); + } + + return flags; +} + +TagLib::uint Ogg::Page::packetCount() const +{ + return d->header.packetSizes().size(); +} + +ByteVectorList Ogg::Page::packets() const +{ + if(!d->packets.isEmpty()) + return d->packets; + + ByteVectorList l; + + if(d->file && d->header.isValid()) { + + d->file->seek(d->packetOffset); + + List packetSizes = d->header.packetSizes(); + + List::ConstIterator it = packetSizes.begin(); + for(; it != packetSizes.end(); ++it) + l.append(d->file->readBlock(*it)); + } + else + debug("Ogg::Page::packets() -- attempting to read packets from an invalid page."); + + return l; +} + +int Ogg::Page::size() const +{ + return d->header.size() + d->header.dataSize(); +} + +ByteVector Ogg::Page::render() const +{ + ByteVector data; + + data.append(d->header.render()); + + if(d->packets.isEmpty()) { + if(d->file) { + d->file->seek(d->packetOffset); + data.append(d->file->readBlock(d->dataSize)); + } + else + debug("Ogg::Page::render() -- this page is empty!"); + } + else { + ByteVectorList::ConstIterator it = d->packets.begin(); + for(; it != d->packets.end(); ++it) + data.append(*it); + } + + // Compute and set the checksum for the Ogg page. The checksum is taken over + // the entire page with the 4 bytes reserved for the checksum zeroed and then + // inserted in bytes 22-25 of the page header. + + ByteVector checksum = ByteVector::fromUInt(data.checksum(), false); + for(int i = 0; i < 4; i++) + data[i + 22] = checksum[i]; + + return data; +} + +List Ogg::Page::paginate(const ByteVectorList &packets, + PaginationStrategy strategy, + uint streamSerialNumber, + int firstPage, + bool firstPacketContinued, + bool lastPacketCompleted, + bool containsLastPacket) +{ + List l; + + int totalSize = 0; + + for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) + totalSize += (*it).size(); + + if(strategy == Repaginate || totalSize + packets.size() > 255 * 256) { + debug("Ogg::Page::paginate() -- Sorry! Repagination is not yet implemented."); + return l; + } + + // TODO: Handle creation of multiple pages here with appropriate pagination. + + Page *p = new Page(packets, streamSerialNumber, firstPage, firstPacketContinued, + lastPacketCompleted, containsLastPacket); + l.append(p); + + return l; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::Page::Page(const ByteVectorList &packets, + uint streamSerialNumber, + int pageNumber, + bool firstPacketContinued, + bool lastPacketCompleted, + bool containsLastPacket) +{ + d = new PagePrivate; + + ByteVector data; + List packetSizes; + + d->header.setFirstPageOfStream(pageNumber == 0 && !firstPacketContinued); + d->header.setLastPageOfStream(containsLastPacket); + d->header.setFirstPacketContinued(firstPacketContinued); + d->header.setLastPacketCompleted(lastPacketCompleted); + d->header.setStreamSerialNumber(streamSerialNumber); + d->header.setPageSequenceNumber(pageNumber); + + // Build a page from the list of packets. + + for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { + packetSizes.append((*it).size()); + data.append(*it); + } + d->packets = packets; + d->header.setPacketSizes(packetSizes); +} diff --git a/Libraries/TagLib/Files/taglib/ogg/oggpage.h b/Libraries/TagLib/Files/taglib/ogg/oggpage.h new file mode 100644 index 000000000..c4b0792a2 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/oggpage.h @@ -0,0 +1,198 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_OGGPAGE_H +#define TAGLIB_OGGPAGE_H + +#include + +namespace TagLib { + + namespace Ogg { + + class File; + class PageHeader; + + //! An implementation of Ogg pages + + /*! + * This is an implementation of the pages that make up an Ogg stream. + * This handles parsing pages and breaking them down into packets and handles + * the details of packets spanning multiple pages and pages that contiain + * multiple packets. + * + * In most Xiph.org formats the comments are found in the first few packets, + * this however is a reasonably complete implementation of Ogg pages that + * could potentially be useful for non-meta data purposes. + */ + + class Page + { + public: + /*! + * Read an Ogg page from the \a file at the position \a pageOffset. + */ + Page(File *file, long pageOffset); + + virtual ~Page(); + + /*! + * Returns the page's position within the file (in bytes). + */ + long fileOffset() const; + + /*! + * Returns a pointer to the header for this page. This pointer will become + * invalid when the page is deleted. + */ + const PageHeader *header() const; + + /*! + * Returns the index of the first packet wholly or partially contained in + * this page. + * + * \see setFirstPacketIndex() + */ + int firstPacketIndex() const; + + /*! + * Sets the index of the first packet in the page. + * + * \see firstPacketIndex() + */ + void setFirstPacketIndex(int index); + + /*! + * When checking to see if a page contains a given packet this set of flags + * represents the possible values for that packets status in the page. + * + * \see containsPacket() + */ + enum ContainsPacketFlags { + //! No part of the packet is contained in the page + DoesNotContainPacket = 0x0000, + //! The packet is wholly contained in the page + CompletePacket = 0x0001, + //! The page starts with the given packet + BeginsWithPacket = 0x0002, + //! The page ends with the given packet + EndsWithPacket = 0x0004 + }; + + /*! + * Checks to see if the specified \a packet is contained in the current + * page. + * + * \see ContainsPacketFlags + */ + ContainsPacketFlags containsPacket(int index) const; + + /*! + * Returns the number of packets (whole or partial) in this page. + */ + uint packetCount() const; + + /*! + * Returns a list of the packets in this page. + * + * \note Either or both the first and last packets may be only partial. + * \see PageHeader::firstPacketContinued() + */ + ByteVectorList packets() const; + + /*! + * Returns the size of the page in bytes. + */ + int size() const; + + ByteVector render() const; + + /*! + * Defines a strategy for pagination, or grouping pages into Ogg packets, + * for use with pagination methods. + * + * \note Yes, I'm aware that this is not a canonical "Strategy Pattern", + * the term was simply convenient. + */ + enum PaginationStrategy { + /*! + * Attempt to put the specified set of packets into a single Ogg packet. + * If the sum of the packet data is greater than will fit into a single + * Ogg page -- 65280 bytes -- this will fall back to repagination using + * the recommended page sizes. + */ + SinglePagePerGroup, + /*! + * Split the packet or group of packets into pages that conform to the + * sizes recommended in the Ogg standard. + */ + Repaginate + }; + + /*! + * Pack \a packets into Ogg pages using the \a strategy for pagination. + * The page number indicater inside of the rendered packets will start + * with \a firstPage and be incremented for each page rendered. + * \a containsLastPacket should be set to true if \a packets contains the + * last page in the stream and will set the appropriate flag in the last + * rendered Ogg page's header. \a streamSerialNumber should be set to + * the serial number for this stream. + * + * \note The "absolute granule position" is currently always zeroed using + * this method as this suffices for the comment headers. + * + * \warning The pages returned by this method must be deleted by the user. + * You can use List::setAutoDelete(true) to set these pages to be + * automatically deleted when this list passes out of scope. + * + * \see PaginationStrategy + * \see List::setAutoDelete() + */ + static List paginate(const ByteVectorList &packets, + PaginationStrategy strategy, + uint streamSerialNumber, + int firstPage, + bool firstPacketContinued = false, + bool lastPacketCompleted = true, + bool containsLastPacket = false); + + protected: + /*! + * Creates an Ogg packet based on the data in \a packets. The page number + * for each page will be set to \a pageNumber. + */ + Page(const ByteVectorList &packets, + uint streamSerialNumber, + int pageNumber, + bool firstPacketContinued = false, + bool lastPacketCompleted = true, + bool containsLastPacket = false); + + private: + Page(const Page &); + Page &operator=(const Page &); + + class PagePrivate; + PagePrivate *d; + }; + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/ogg/oggpageheader.cpp b/Libraries/TagLib/Files/taglib/ogg/oggpageheader.cpp new file mode 100644 index 000000000..40fe92dca --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/oggpageheader.cpp @@ -0,0 +1,317 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include +#include +#include + +#include "oggpageheader.h" +#include "oggfile.h" + +using namespace TagLib; + +class Ogg::PageHeader::PageHeaderPrivate +{ +public: + PageHeaderPrivate(File *f, long pageOffset) : + file(f), + fileOffset(pageOffset), + isValid(false), + firstPacketContinued(false), + lastPacketCompleted(false), + firstPageOfStream(false), + lastPageOfStream(false), + absoluteGranularPosition(0), + streamSerialNumber(0), + pageSequenceNumber(-1), + size(0), + dataSize(0) + {} + + File *file; + long fileOffset; + bool isValid; + List packetSizes; + bool firstPacketContinued; + bool lastPacketCompleted; + bool firstPageOfStream; + bool lastPageOfStream; + long long absoluteGranularPosition; + uint streamSerialNumber; + int pageSequenceNumber; + int size; + int dataSize; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::PageHeader::PageHeader(Ogg::File *file, long pageOffset) +{ + d = new PageHeaderPrivate(file, pageOffset); + if(file && pageOffset >= 0) + read(); +} + +Ogg::PageHeader::~PageHeader() +{ + delete d; +} + +bool Ogg::PageHeader::isValid() const +{ + return d->isValid; +} + +List Ogg::PageHeader::packetSizes() const +{ + return d->packetSizes; +} + +void Ogg::PageHeader::setPacketSizes(const List &sizes) +{ + d->packetSizes = sizes; +} + +bool Ogg::PageHeader::firstPacketContinued() const +{ + return d->firstPacketContinued; +} + +void Ogg::PageHeader::setFirstPacketContinued(bool continued) +{ + d->firstPacketContinued = continued; +} + +bool Ogg::PageHeader::lastPacketCompleted() const +{ + return d->lastPacketCompleted; +} + +void Ogg::PageHeader::setLastPacketCompleted(bool completed) +{ + d->lastPacketCompleted = completed; +} + +bool Ogg::PageHeader::firstPageOfStream() const +{ + return d->firstPageOfStream; +} + +void Ogg::PageHeader::setFirstPageOfStream(bool first) +{ + d->firstPageOfStream = first; +} + +bool Ogg::PageHeader::lastPageOfStream() const +{ + return d->lastPageOfStream; +} + +void Ogg::PageHeader::setLastPageOfStream(bool last) +{ + d->lastPageOfStream = last; +} + +long long Ogg::PageHeader::absoluteGranularPosition() const +{ + return d->absoluteGranularPosition; +} + +void Ogg::PageHeader::setAbsoluteGranularPosition(long long agp) +{ + d->absoluteGranularPosition = agp; +} + +int Ogg::PageHeader::pageSequenceNumber() const +{ + return d->pageSequenceNumber; +} + +void Ogg::PageHeader::setPageSequenceNumber(int sequenceNumber) +{ + d->pageSequenceNumber = sequenceNumber; +} + +TagLib::uint Ogg::PageHeader::streamSerialNumber() const +{ + return d->streamSerialNumber; +} + +void Ogg::PageHeader::setStreamSerialNumber(uint n) +{ + d->streamSerialNumber = n; +} + +int Ogg::PageHeader::size() const +{ + return d->size; +} + +int Ogg::PageHeader::dataSize() const +{ + return d->dataSize; +} + +ByteVector Ogg::PageHeader::render() const +{ + ByteVector data; + + // capture patern + + data.append("OggS"); + + // stream structure version + + data.append(char(0)); + + // header type flag + + std::bitset<8> flags; + flags[0] = d->firstPacketContinued; + flags[1] = d->pageSequenceNumber == 0; + flags[2] = d->lastPageOfStream; + + data.append(char(flags.to_ulong())); + + // absolute granular position + + data.append(ByteVector::fromLongLong(d->absoluteGranularPosition, false)); + + // stream serial number + + data.append(ByteVector::fromUInt(d->streamSerialNumber, false)); + + // page sequence number + + data.append(ByteVector::fromUInt(d->pageSequenceNumber, false)); + + // checksum -- this is left empty and should be filled in by the Ogg::Page + // class + + data.append(ByteVector(4, 0)); + + // page segment count and page segment table + + ByteVector pageSegments = lacingValues(); + + data.append(char(uchar(pageSegments.size()))); + data.append(pageSegments); + + return data; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void Ogg::PageHeader::read() +{ + d->file->seek(d->fileOffset); + + // An Ogg page header is at least 27 bytes, so we'll go ahead and read that + // much and then get the rest when we're ready for it. + + ByteVector data = d->file->readBlock(27); + + // Sanity check -- make sure that we were in fact able to read as much data as + // we asked for and that the page begins with "OggS". + + if(data.size() != 27 || data.mid(0, 4) != "OggS") { + debug("Ogg::PageHeader::read() -- error reading page header"); + return; + } + + std::bitset<8> flags(data[5]); + + d->firstPacketContinued = flags.test(0); + d->firstPageOfStream = flags.test(1); + d->lastPageOfStream = flags.test(2); + + d->absoluteGranularPosition = data.mid(6, 8).toLongLong(false); + d->streamSerialNumber = data.mid(14, 4).toUInt(false); + d->pageSequenceNumber = data.mid(18, 4).toUInt(false); + + // Byte number 27 is the number of page segments, which is the only variable + // length portion of the page header. After reading the number of page + // segments we'll then read in the coresponding data for this count. + + int pageSegmentCount = uchar(data[26]); + + ByteVector pageSegments = d->file->readBlock(pageSegmentCount); + + // Another sanity check. + + if(pageSegmentCount < 1 || int(pageSegments.size()) != pageSegmentCount) + return; + + // The base size of an Ogg page 27 bytes plus the number of lacing values. + + d->size = 27 + pageSegmentCount; + + int packetSize = 0; + + for(int i = 0; i < pageSegmentCount; i++) { + d->dataSize += uchar(pageSegments[i]); + packetSize += uchar(pageSegments[i]); + + if(uchar(pageSegments[i]) < 255) { + d->packetSizes.append(packetSize); + packetSize = 0; + } + } + + if(packetSize > 0) { + d->packetSizes.append(packetSize); + d->lastPacketCompleted = false; + } + else + d->lastPacketCompleted = true; + + d->isValid = true; +} + +ByteVector Ogg::PageHeader::lacingValues() const +{ + ByteVector data; + + List sizes = d->packetSizes; + for(List::ConstIterator it = sizes.begin(); it != sizes.end(); ++it) { + + // The size of a packet in an Ogg page is indicated by a series of "lacing + // values" where the sum of the values is the packet size in bytes. Each of + // these values is a byte. A value of less than 255 (0xff) indicates the end + // of the packet. + + div_t n = div(*it, 255); + + for(int i = 0; i < n.quot; i++) + data.append(char(uchar(255))); + + if(it != --sizes.end() || d->lastPacketCompleted) + data.append(char(uchar(n.rem))); + } + + return data; +} diff --git a/Libraries/TagLib/Files/taglib/ogg/oggpageheader.h b/Libraries/TagLib/Files/taglib/ogg/oggpageheader.h new file mode 100644 index 000000000..45f22a83e --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/oggpageheader.h @@ -0,0 +1,227 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_OGGPAGEHEADER_H +#define TAGLIB_OGGPAGEHEADER_H + +#include +#include + +namespace TagLib { + + namespace Ogg { + + class File; + + //! An implementation of the page headers associated with each Ogg::Page + + /*! + * This class implements Ogg page headers which contain the information + * about Ogg pages needed to break them into packets which can be passed on + * to the codecs. + */ + + class PageHeader + { + public: + /*! + * Reads a PageHeader from \a file starting at \a pageOffset. The defaults + * create a page with no (and as such, invalid) data that must be set + * later. + */ + PageHeader(File *file = 0, long pageOffset = -1); + + /*! + * Deletes this instance of the PageHeader. + */ + virtual ~PageHeader(); + + /*! + * Returns true if the header parsed properly and is valid. + */ + bool isValid() const; + + /*! + * Ogg pages contain a list of packets (which are used by the contained + * codecs). The sizes of these pages is encoded in the page header. This + * returns a list of the packet sizes in bytes. + * + * \see setPacketSizes() + */ + List packetSizes() const; + + /*! + * Sets the sizes of the packets in this page to \a sizes. Internally this + * updates the lacing values in the header. + * + * \see packetSizes() + */ + void setPacketSizes(const List &sizes); + + /*! + * Some packets can be continued across multiple pages. If the + * first packet in the current page is a continuation this will return + * true. If this is page starts with a new packet this will return false. + * + * \see lastPacketCompleted() + * \see setFirstPacketContinued() + */ + bool firstPacketContinued() const; + + /*! + * Sets the internal flag indicating if the first packet in this page is + * continued to \a continued. + * + * \see firstPacketContinued() + */ + void setFirstPacketContinued(bool continued); + + /*! + * Returns true if the last packet of this page is completely contained in + * this page. + * + * \see firstPacketContinued() + * \see setLastPacketCompleted() + */ + bool lastPacketCompleted() const; + + /*! + * Sets the internal flag indicating if the last packet in this page is + * complete to \a completed. + * + * \see lastPacketCompleted() + */ + void setLastPacketCompleted(bool completed); + + /*! + * This returns true if this is the first page of the Ogg (logical) stream. + * + * \see setFirstPageOfStream() + */ + bool firstPageOfStream() const; + + /*! + * Marks this page as the first page of the Ogg stream. + * + * \see firstPageOfStream() + */ + void setFirstPageOfStream(bool first); + + /*! + * This returns true if this is the last page of the Ogg (logical) stream. + * + * \see setLastPageOfStream() + */ + bool lastPageOfStream() const; + + /*! + * Marks this page as the last page of the Ogg stream. + * + * \see lastPageOfStream() + */ + void setLastPageOfStream(bool last); + + /*! + * A special value of containing the position of the packet to be + * interpreted by the codec. In the case of Vorbis this contains the PCM + * value and is used to calculate the length of the stream. + * + * \see setAbsoluteGranularPosition() + */ + long long absoluteGranularPosition() const; + + /*! + * A special value of containing the position of the packet to be + * interpreted by the codec. It is only supported here so that it may be + * coppied from one page to another. + * + * \see absoluteGranularPosition() + */ + void setAbsoluteGranularPosition(long long agp); + + /*! + * Every Ogg logical stream is given a random serial number which is common + * to every page in that logical stream. This returns the serial number of + * the stream associated with this packet. + * + * \see setStreamSerialNumber() + */ + uint streamSerialNumber() const; + + /*! + * Every Ogg logical stream is given a random serial number which is common + * to every page in that logical stream. This sets this pages serial + * number. This method should be used when adding new pages to a logical + * stream. + * + * \see streamSerialNumber() + */ + void setStreamSerialNumber(uint n); + + /*! + * Returns the index of the page within the Ogg stream. This helps make it + * possible to determine if pages have been lost. + * + * \see setPageSequenceNumber() + */ + int pageSequenceNumber() const; + + /*! + * Sets the page's position in the stream to \a sequenceNumber. + * + * \see pageSequenceNumber() + */ + void setPageSequenceNumber(int sequenceNumber); + + /*! + * Returns the complete header size. + */ + int size() const; + + /*! + * Returns the size of the data portion of the page -- i.e. the size of the + * page less the header size. + */ + int dataSize() const; + + /*! + * Render the page header to binary data. + * + * \note The checksum -- bytes 22 - 25 -- will be left empty and must be + * filled in when rendering the entire page. + */ + ByteVector render() const; + + private: + PageHeader(const PageHeader &); + PageHeader &operator=(const PageHeader &); + + void read(); + ByteVector lacingValues() const; + + class PageHeaderPrivate; + PageHeaderPrivate *d; + }; + + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/ogg/vorbis/Makefile.am b/Libraries/TagLib/Files/taglib/ogg/vorbis/Makefile.am new file mode 100644 index 000000000..4a6393c1f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/vorbis/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ogg \ + $(all_includes) + +noinst_LTLIBRARIES = libvorbis.la + +libvorbis_la_SOURCES = vorbisfile.cpp vorbisproperties.cpp + +taglib_include_HEADERS = vorbisfile.h vorbisproperties.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libvorbis_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/ogg/vorbis/Makefile.in b/Libraries/TagLib/Files/taglib/ogg/vorbis/Makefile.in new file mode 100644 index 000000000..47b11cca4 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/vorbis/Makefile.in @@ -0,0 +1,548 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ogg \ + $(all_includes) + + +noinst_LTLIBRARIES = libvorbis.la + +libvorbis_la_SOURCES = vorbisfile.cpp vorbisproperties.cpp + +taglib_include_HEADERS = vorbisfile.h vorbisproperties.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libvorbis_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/ogg/vorbis +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libvorbis_la_LDFLAGS = +libvorbis_la_LIBADD = +am_libvorbis_la_OBJECTS = vorbisfile.lo vorbisproperties.lo +#>- libvorbis_la_OBJECTS = $(am_libvorbis_la_OBJECTS) +#>+ 4 +libvorbis_la_final_OBJECTS = libvorbis_la.all_cpp.lo +libvorbis_la_nofinal_OBJECTS = vorbisfile.lo vorbisproperties.lo +@KDE_USE_FINAL_FALSE@libvorbis_la_OBJECTS = $(libvorbis_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libvorbis_la_OBJECTS = $(libvorbis_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/vorbisfile.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/vorbisproperties.Plo +#>+ 5 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libvorbis_la.all_cpp.P ./$(DEPDIR)/vorbisfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/vorbisproperties.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/vorbisfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/vorbisproperties.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libvorbis_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(libvorbis_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/ogg/vorbis/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ogg/vorbis/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ogg/vorbis/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libvorbis.la: $(libvorbis_la_OBJECTS) $(libvorbis_la_DEPENDENCIES) + $(CXXLINK) $(libvorbis_la_LDFLAGS) $(libvorbis_la_OBJECTS) $(libvorbis_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vorbisfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vorbisproperties.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/ogg/vorbis/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/ogg/vorbis/Makefile.in + + +#>+ 11 +libvorbis_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/vorbisfile.cpp $(srcdir)/vorbisproperties.cpp + @echo 'creating libvorbis_la.all_cpp.cpp ...'; \ + rm -f libvorbis_la.all_cpp.files libvorbis_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libvorbis_la.all_cpp.final; \ + for file in vorbisfile.cpp vorbisproperties.cpp ; do \ + echo "#include \"$$file\"" >> libvorbis_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libvorbis_la.all_cpp.final; \ + done; \ + cat libvorbis_la.all_cpp.final libvorbis_la.all_cpp.files > libvorbis_la.all_cpp.cpp; \ + rm -f libvorbis_la.all_cpp.final libvorbis_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libvorbis_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libvorbis_la_OBJECTS="$(libvorbis_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libvorbis_la_OBJECTS="$(libvorbis_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libvorbis_la_OBJECTS="$(libvorbis_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libvorbis_la_OBJECTS="$(libvorbis_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisfile.cpp b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisfile.cpp new file mode 100644 index 000000000..a6e8b94c9 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisfile.cpp @@ -0,0 +1,113 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include +#include + +#include "vorbisfile.h" + +using namespace TagLib; + +class Vorbis::File::FilePrivate +{ +public: + FilePrivate() : + comment(0), + properties(0) {} + + ~FilePrivate() + { + delete comment; + delete properties; + } + + Ogg::XiphComment *comment; + Properties *properties; +}; + +namespace TagLib { + /*! + * Vorbis headers can be found with one type ID byte and the string "vorbis" in + * an Ogg stream. 0x03 indicates the comment header. + */ + static const char vorbisCommentHeaderID[] = { 0x03, 'v', 'o', 'r', 'b', 'i', 's', 0 }; +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Vorbis::File::File(const char *file, bool readProperties, + Properties::ReadStyle propertiesStyle) : Ogg::File(file) +{ + d = new FilePrivate; + read(readProperties, propertiesStyle); +} + +Vorbis::File::~File() +{ + delete d; +} + +Ogg::XiphComment *Vorbis::File::tag() const +{ + return d->comment; +} + +Vorbis::Properties *Vorbis::File::audioProperties() const +{ + return d->properties; +} + +bool Vorbis::File::save() +{ + ByteVector v(vorbisCommentHeaderID); + + if(!d->comment) + d->comment = new Ogg::XiphComment; + v.append(d->comment->render()); + + setPacket(1, v); + + return Ogg::File::save(); +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void Vorbis::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) +{ + ByteVector commentHeaderData = packet(1); + + if(commentHeaderData.mid(0, 7) != vorbisCommentHeaderID) { + debug("Vorbis::File::read() - Could not find the Vorbis comment header."); + setValid(false); + return; + } + + d->comment = new Ogg::XiphComment(commentHeaderData.mid(7)); + + if(readProperties) + d->properties = new Properties(this, propertiesStyle); +} diff --git a/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisfile.h b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisfile.h new file mode 100644 index 000000000..f85e4bee6 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisfile.h @@ -0,0 +1,113 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_VORBISFILE_H +#define TAGLIB_VORBISFILE_H + +#include +#include + +#include "vorbisproperties.h" + +namespace TagLib { + +/* + * This is just to make this appear to be in the Ogg namespace in the + * documentation. The typedef below will make this work with the current code. + * In the next BIC version of TagLib this will be really moved into the Ogg + * namespace. + */ + +#ifdef DOXYGEN + namespace Ogg { +#endif + + //! A namespace containing classes for Vorbis metadata + + namespace Vorbis { + + + //! An implementation of Ogg::File with Vorbis specific methods + + /*! + * This is the central class in the Ogg Vorbis metadata processing collection + * of classes. It's built upon Ogg::File which handles processing of the Ogg + * logical bitstream and breaking it down into pages which are handled by + * the codec implementations, in this case Vorbis specifically. + */ + + class File : public Ogg::File + { + public: + /*! + * Contructs a Vorbis file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + */ + File(const char *file, bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns the XiphComment for this file. XiphComment implements the tag + * interface, so this serves as the reimplementation of + * TagLib::File::tag(). + */ + virtual Ogg::XiphComment *tag() const; + + /*! + * Returns the Vorbis::Properties for this file. If no audio properties + * were read then this will return a null pointer. + */ + virtual Properties *audioProperties() const; + + virtual bool save(); + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + + class FilePrivate; + FilePrivate *d; + }; + } + +/* + * To keep compatibility with the current version put Vorbis in the Ogg namespace + * only in the docs and provide a typedef to make it work. In the next BIC + * version this will be removed and it will only exist in the Ogg namespace. + */ + +#ifdef DOXYGEN + } +#else + namespace Ogg { namespace Vorbis { typedef TagLib::Vorbis::File File; } } +#endif + +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisproperties.cpp b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisproperties.cpp new file mode 100644 index 000000000..bee7f8d69 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisproperties.cpp @@ -0,0 +1,179 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include + +#include "vorbisproperties.h" +#include "vorbisfile.h" + +using namespace TagLib; + +class Vorbis::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate(File *f, ReadStyle s) : + file(f), + style(s), + length(0), + bitrate(0), + sampleRate(0), + channels(0), + vorbisVersion(0), + bitrateMaximum(0), + bitrateNominal(0), + bitrateMinimum(0) {} + + File *file; + ReadStyle style; + int length; + int bitrate; + int sampleRate; + int channels; + int vorbisVersion; + int bitrateMaximum; + int bitrateNominal; + int bitrateMinimum; +}; + +namespace TagLib { + /*! + * Vorbis headers can be found with one type ID byte and the string "vorbis" in + * an Ogg stream. 0x01 indicates the setup header. + */ + static const char vorbisSetupHeaderID[] = { 0x01, 'v', 'o', 'r', 'b', 'i', 's', 0 }; +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Vorbis::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) +{ + d = new PropertiesPrivate(file, style); + read(); +} + +Vorbis::Properties::~Properties() +{ + delete d; +} + +int Vorbis::Properties::length() const +{ + return d->length; +} + +int Vorbis::Properties::bitrate() const +{ + return int(float(d->bitrate) / float(1000) + 0.5); +} + +int Vorbis::Properties::sampleRate() const +{ + return d->sampleRate; +} + +int Vorbis::Properties::channels() const +{ + return d->channels; +} + +int Vorbis::Properties::vorbisVersion() const +{ + return d->vorbisVersion; +} + +int Vorbis::Properties::bitrateMaximum() const +{ + return d->bitrateMaximum; +} + +int Vorbis::Properties::bitrateNominal() const +{ + return d->bitrateNominal; +} + +int Vorbis::Properties::bitrateMinimum() const +{ + return d->bitrateMinimum; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void Vorbis::Properties::read() +{ + // Get the identification header from the Ogg implementation. + + ByteVector data = d->file->packet(0); + + int pos = 0; + + if(data.mid(pos, 7) != vorbisSetupHeaderID) { + debug("Vorbis::Properties::read() -- invalid Vorbis identification header"); + return; + } + + pos += 7; + + d->vorbisVersion = data.mid(pos, 4).toUInt(false); + pos += 4; + + d->channels = uchar(data[pos]); + pos += 1; + + d->sampleRate = data.mid(pos, 4).toUInt(false); + pos += 4; + + d->bitrateMaximum = data.mid(pos, 4).toUInt(false); + pos += 4; + + d->bitrateNominal = data.mid(pos, 4).toUInt(false); + pos += 4; + + d->bitrateMinimum = data.mid(pos, 4).toUInt(false); + + // TODO: Later this should be only the "fast" mode. + d->bitrate = d->bitrateNominal; + + // Find the length of the file. See http://wiki.xiph.org/VorbisStreamLength/ + // for my notes on the topic. + + const Ogg::PageHeader *first = d->file->firstPageHeader(); + const Ogg::PageHeader *last = d->file->lastPageHeader(); + + if(first && last) { + long long start = first->absoluteGranularPosition(); + long long end = last->absoluteGranularPosition(); + + if(start >= 0 && end >= 0 && d->sampleRate > 0) + d->length = (end - start) / (long long) d->sampleRate; + else + debug("Vorbis::Properties::read() -- Either the PCM values for the start or " + "end of this file was incorrect or the sample rate is zero."); + } + else + debug("Vorbis::Properties::read() -- Could not find valid first and last Ogg pages."); +} diff --git a/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisproperties.h b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisproperties.h new file mode 100644 index 000000000..01dffed94 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/vorbis/vorbisproperties.h @@ -0,0 +1,120 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_VORBISPROPERTIES_H +#define TAGLIB_VORBISPROPERTIES_H + +#include + +namespace TagLib { + +/* + * This is just to make this appear to be in the Ogg namespace in the + * documentation. The typedef below will make this work with the current code. + * In the next BIC version of TagLib this will be really moved into the Ogg + * namespace. + */ + +#ifdef DOXYGEN + namespace Ogg { +#endif + + namespace Vorbis { + + class File; + + //! An implementation of audio property reading for Ogg Vorbis + + /*! + * This reads the data from an Ogg Vorbis stream found in the AudioProperties + * API. + */ + + class Properties : public AudioProperties + { + public: + /*! + * Create an instance of Vorbis::Properties with the data read from the + * Vorbis::File \a file. + */ + Properties(File *file, ReadStyle style = Average); + + /*! + * Destroys this VorbisProperties instance. + */ + virtual ~Properties(); + + // Reimplementations. + + virtual int length() const; + virtual int bitrate() const; + virtual int sampleRate() const; + virtual int channels() const; + + /*! + * Returns the Vorbis version, currently "0" (as specified by the spec). + */ + int vorbisVersion() const; + + /*! + * Returns the maximum bitrate as read from the Vorbis identification + * header. + */ + int bitrateMaximum() const; + + /*! + * Returns the nominal bitrate as read from the Vorbis identification + * header. + */ + int bitrateNominal() const; + + /*! + * Returns the minimum bitrate as read from the Vorbis identification + * header. + */ + int bitrateMinimum() const; + + private: + Properties(const Properties &); + Properties &operator=(const Properties &); + + void read(); + + class PropertiesPrivate; + PropertiesPrivate *d; + }; + } + +/* + * To keep compatibility with the current version put Vorbis in the Ogg namespace + * only in the docs and provide a typedef to make it work. In the next BIC + * version this will be removed and it will only exist in the Ogg namespace. + */ + +#ifdef DOXYGEN + } +#else + namespace Ogg { namespace Vorbis { typedef TagLib::AudioProperties AudioProperties; } } +#endif + +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/ogg/xiphcomment.cpp b/Libraries/TagLib/Files/taglib/ogg/xiphcomment.cpp new file mode 100644 index 000000000..62c45ec41 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/xiphcomment.cpp @@ -0,0 +1,293 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include + +using namespace TagLib; + +class Ogg::XiphComment::XiphCommentPrivate +{ +public: + FieldListMap fieldListMap; + String vendorID; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::XiphComment::XiphComment() : TagLib::Tag() +{ + d = new XiphCommentPrivate; +} + +Ogg::XiphComment::XiphComment(const ByteVector &data) : TagLib::Tag() +{ + d = new XiphCommentPrivate; + parse(data); +} + +Ogg::XiphComment::~XiphComment() +{ + delete d; +} + +String Ogg::XiphComment::title() const +{ + if(d->fieldListMap["TITLE"].isEmpty()) + return String::null; + return d->fieldListMap["TITLE"].front(); +} + +String Ogg::XiphComment::artist() const +{ + if(d->fieldListMap["ARTIST"].isEmpty()) + return String::null; + return d->fieldListMap["ARTIST"].front(); +} + +String Ogg::XiphComment::album() const +{ + if(d->fieldListMap["ALBUM"].isEmpty()) + return String::null; + return d->fieldListMap["ALBUM"].front(); +} + +String Ogg::XiphComment::comment() const +{ + if(d->fieldListMap["DESCRIPTION"].isEmpty()) + return String::null; + return d->fieldListMap["DESCRIPTION"].front(); +} + +String Ogg::XiphComment::genre() const +{ + if(d->fieldListMap["GENRE"].isEmpty()) + return String::null; + return d->fieldListMap["GENRE"].front(); +} + +TagLib::uint Ogg::XiphComment::year() const +{ + if(d->fieldListMap["DATE"].isEmpty()) + return 0; + return d->fieldListMap["DATE"].front().toInt(); +} + +TagLib::uint Ogg::XiphComment::track() const +{ + if(d->fieldListMap["TRACKNUMBER"].isEmpty()) + return 0; + return d->fieldListMap["TRACKNUMBER"].front().toInt(); +} + +void Ogg::XiphComment::setTitle(const String &s) +{ + addField("TITLE", s); +} + +void Ogg::XiphComment::setArtist(const String &s) +{ + addField("ARTIST", s); +} + +void Ogg::XiphComment::setAlbum(const String &s) +{ + addField("ALBUM", s); +} + +void Ogg::XiphComment::setComment(const String &s) +{ + addField("DESCRIPTION", s); +} + +void Ogg::XiphComment::setGenre(const String &s) +{ + addField("GENRE", s); +} + +void Ogg::XiphComment::setYear(uint i) +{ + if(i == 0) + removeField("DATE"); + else + addField("DATE", String::number(i)); +} + +void Ogg::XiphComment::setTrack(uint i) +{ + if(i == 0) + removeField("TRACKNUMBER"); + else + addField("TRACKNUMBER", String::number(i)); +} + +bool Ogg::XiphComment::isEmpty() const +{ + FieldListMap::ConstIterator it = d->fieldListMap.begin(); + for(; it != d->fieldListMap.end(); ++it) + if(!(*it).second.isEmpty()) + return false; + + return true; +} + +TagLib::uint Ogg::XiphComment::fieldCount() const +{ + uint count = 0; + + FieldListMap::ConstIterator it = d->fieldListMap.begin(); + for(; it != d->fieldListMap.end(); ++it) + count += (*it).second.size(); + + return count; +} + +const Ogg::FieldListMap &Ogg::XiphComment::fieldListMap() const +{ + return d->fieldListMap; +} + +String Ogg::XiphComment::vendorID() const +{ + return d->vendorID; +} + +void Ogg::XiphComment::addField(const String &key, const String &value, bool replace) +{ + if(replace) + removeField(key.upper()); + + if(!key.isEmpty()) + d->fieldListMap[key.upper()].append(value); +} + +void Ogg::XiphComment::removeField(const String &key, const String &value) +{ + if(!value.isNull()) { + StringList::Iterator it = d->fieldListMap[key].begin(); + for(; it != d->fieldListMap[key].end(); ++it) { + if(value == *it) + d->fieldListMap[key].erase(it); + } + } + else + d->fieldListMap[key].clear(); +} + +ByteVector Ogg::XiphComment::render() const +{ + return render(true); +} + +ByteVector Ogg::XiphComment::render(bool addFramingBit) const +{ + ByteVector data; + + // Add the vendor ID length and the vendor ID. It's important to use the + // lenght of the data(String::UTF8) rather than the lenght of the the string + // since this is UTF8 text and there may be more characters in the data than + // in the UTF16 string. + + ByteVector vendorData = d->vendorID.data(String::UTF8); + + data.append(ByteVector::fromUInt(vendorData.size(), false)); + data.append(vendorData); + + // Add the number of fields. + + data.append(ByteVector::fromUInt(fieldCount(), false)); + + // Iterate over the the field lists. Our iterator returns a + // std::pair where the first String is the field name and + // the StringList is the values associated with that field. + + FieldListMap::ConstIterator it = d->fieldListMap.begin(); + for(; it != d->fieldListMap.end(); ++it) { + + // And now iterate over the values of the current list. + + String fieldName = (*it).first; + StringList values = (*it).second; + + StringList::ConstIterator valuesIt = values.begin(); + for(; valuesIt != values.end(); ++valuesIt) { + ByteVector fieldData = fieldName.data(String::UTF8); + fieldData.append('='); + fieldData.append((*valuesIt).data(String::UTF8)); + + data.append(ByteVector::fromUInt(fieldData.size(), false)); + data.append(fieldData); + } + } + + // Append the "framing bit". + + if(addFramingBit) + data.append(char(1)); + + return data; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void Ogg::XiphComment::parse(const ByteVector &data) +{ + // The first thing in the comment data is the vendor ID length, followed by a + // UTF8 string with the vendor ID. + + int pos = 0; + + int vendorLength = data.mid(0, 4).toUInt(false); + pos += 4; + + d->vendorID = String(data.mid(pos, vendorLength), String::UTF8); + pos += vendorLength; + + // Next the number of fields in the comment vector. + + int commentFields = data.mid(pos, 4).toUInt(false); + pos += 4; + + for(int i = 0; i < commentFields; i++) { + + // Each comment field is in the format "KEY=value" in a UTF8 string and has + // 4 bytes before the text starts that gives the length. + + int commentLength = data.mid(pos, 4).toUInt(false); + pos += 4; + + String comment = String(data.mid(pos, commentLength), String::UTF8); + pos += commentLength; + + int commentSeparatorPosition = comment.find("="); + + String key = comment.substr(0, commentSeparatorPosition); + String value = comment.substr(commentSeparatorPosition + 1); + + addField(key, value, false); + } +} diff --git a/Libraries/TagLib/Files/taglib/ogg/xiphcomment.h b/Libraries/TagLib/Files/taglib/ogg/xiphcomment.h new file mode 100644 index 000000000..dbcde9d5e --- /dev/null +++ b/Libraries/TagLib/Files/taglib/ogg/xiphcomment.h @@ -0,0 +1,190 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_VORBISCOMMENT_H +#define TAGLIB_VORBISCOMMENT_H + +#include +#include +#include +#include +#include +#include + +namespace TagLib { + + namespace Ogg { + + /*! + * A mapping between a list of field names, or keys, and a list of values + * associated with that field. + * + * \see XiphComment::fieldListMap() + */ + typedef Map FieldListMap; + + //! Ogg Vorbis comment implementation + + /*! + * This class is an implementation of the Ogg Vorbis comment specification, + * to be found in section 5 of the Ogg Vorbis specification. Because this + * format is also used in other (currently unsupported) Xiph.org formats, it + * has been made part of a generic implementation rather than being limited + * to strictly Vorbis. + * + * Vorbis comments are a simple vector of keys and values, called fields. + * Multiple values for a given key are supported. + * + * \see fieldListMap() + */ + + class XiphComment : public TagLib::Tag + { + public: + /*! + * Constructs an empty Vorbis comment. + */ + XiphComment(); + + /*! + * Constructs a Vorbis comment from \a data. + */ + XiphComment(const ByteVector &data); + + /*! + * Destroys this instance of the XiphComment. + */ + virtual ~XiphComment(); + + virtual String title() const; + virtual String artist() const; + virtual String album() const; + virtual String comment() const; + virtual String genre() const; + virtual uint year() const; + virtual uint track() const; + + virtual void setTitle(const String &s); + virtual void setArtist(const String &s); + virtual void setAlbum(const String &s); + virtual void setComment(const String &s); + virtual void setGenre(const String &s); + virtual void setYear(uint i); + virtual void setTrack(uint i); + + virtual bool isEmpty() const; + + /*! + * Returns the number of fields present in the comment. + */ + uint fieldCount() const; + + /*! + * Returns a reference to the map of field lists. Because Xiph comments + * support multiple fields with the same key, a pure Map would not work. + * As such this is a Map of string lists, keyed on the comment field name. + * + * The standard set of Xiph/Vorbis fields (which may or may not be + * contained in any specific comment) is: + * + *
    + *
  • TITLE
  • + *
  • VERSION
  • + *
  • ALBUM
  • + *
  • ARTIST
  • + *
  • PERFORMER
  • + *
  • COPYRIGHT
  • + *
  • ORGANIZATION
  • + *
  • DESCRIPTION
  • + *
  • GENRE
  • + *
  • DATE
  • + *
  • LOCATION
  • + *
  • CONTACT
  • + *
  • ISRC
  • + *
+ * + * For a more detailed description of these fields, please see the Ogg + * Vorbis specification, section 5.2.2.1. + * + * \note The Ogg Vorbis comment specification does allow these key values + * to be either upper or lower case. However, it is conventional for them + * to be upper case. As such, TagLib, when parsing a Xiph/Vorbis comment, + * converts all fields to uppercase. When you are using this data + * structure, you will need to specify the field name in upper case. + * + * \warning You should not modify this data structure directly, instead + * use addField() and removeField(). + */ + const FieldListMap &fieldListMap() const; + + /*! + * Returns the vendor ID of the Ogg Vorbis encoder. libvorbis 1.0 as the + * most common case always returns "Xiph.Org libVorbis I 20020717". + */ + String vendorID() const; + + /*! + * Add the field specified by \a key with the data \a value. If \a replace + * is true, then all of the other fields with the same key will be removed + * first. + * + * If the field value is empty, the field will be removed. + */ + void addField(const String &key, const String &value, bool replace = true); + + /*! + * Remove the field specified by \a key with the data \a value. If + * \a value is null, all of the fields with the given key will be removed. + */ + void removeField(const String &key, const String &value = String::null); + + /*! + * Renders the comment to a ByteVector suitable for inserting into a file. + */ + ByteVector render() const; // BIC: remove and merge with below + + /*! + * Renders the comment to a ByteVector suitable for inserting into a file. + * + * If \a addFramingBit is true the standard Vorbis comment framing bit will + * be appended. However some formats (notably FLAC) do not work with this + * in place. + */ + ByteVector render(bool addFramingBit) const; + + protected: + /*! + * Reads the tag from the file specified in the constructor and fills the + * FieldListMap. + */ + void parse(const ByteVector &data); + + private: + XiphComment(const XiphComment &); + XiphComment &operator=(const XiphComment &); + + class XiphCommentPrivate; + XiphCommentPrivate *d; + }; + } +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/tag.cpp b/Libraries/TagLib/Files/taglib/tag.cpp new file mode 100644 index 000000000..9ab539b06 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/tag.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "tag.h" + +using namespace TagLib; + +class Tag::TagPrivate +{ + +}; + +Tag::Tag() +{ + +} + +Tag::~Tag() +{ + +} + +bool Tag::isEmpty() const +{ + return (title().isEmpty() && + artist().isEmpty() && + album().isEmpty() && + comment().isEmpty() && + genre().isEmpty() && + year() == 0 && + track() == 0); +} + +void Tag::duplicate(const Tag *source, Tag *target, bool overwrite) // static +{ + if(overwrite) { + target->setTitle(source->title()); + target->setArtist(source->artist()); + target->setAlbum(source->album()); + target->setComment(source->comment()); + target->setGenre(source->genre()); + target->setYear(source->year()); + target->setTrack(source->track()); + } + else { + if(target->title().isEmpty()) + target->setTitle(source->title()); + if(target->artist().isEmpty()) + target->setArtist(source->artist()); + if(target->album().isEmpty()) + target->setAlbum(source->album()); + if(target->comment().isEmpty()) + target->setComment(source->comment()); + if(target->genre().isEmpty()) + target->setGenre(source->genre()); + if(target->year() <= 0) + target->setYear(source->year()); + if(target->track() <= 0) + target->setTrack(source->track()); + } +} diff --git a/Libraries/TagLib/Files/taglib/tag.h b/Libraries/TagLib/Files/taglib/tag.h new file mode 100644 index 000000000..5c9d5a6d3 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/tag.h @@ -0,0 +1,168 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_TAG_H +#define TAGLIB_TAG_H + +#include + +namespace TagLib { + + //! A simple, generic interface to common audio meta data fields + + /*! + * This is an attempt to abstract away the difference in the meta data formats + * of various audio codecs and tagging schemes. As such it is generally a + * subset of what is available in the specific formats but should be suitable + * for most applications. This is meant to complient the generic APIs found + * in TagLib::AudioProperties, TagLib::File and TagLib::FileRef. + */ + + class Tag + { + public: + + /*! + * Detroys this Tag instance. + */ + virtual ~Tag(); + + /*! + * Returns the track name; if no track name is present in the tag + * String::null will be returned. + */ + virtual String title() const = 0; + + /*! + * Returns the artist name; if no artist name is present in the tag + * String::null will be returned. + */ + virtual String artist() const = 0; + + /*! + * Returns the album name; if no album name is present in the tag + * String::null will be returned. + */ + virtual String album() const = 0; + + /*! + * Returns the track comment; if no comment is present in the tag + * String::null will be returned. + */ + virtual String comment() const = 0; + + /*! + * Returns the genre name; if no genre is present in the tag String::null + * will be returned. + */ + virtual String genre() const = 0; + + /*! + * Returns the year; if there is no year set, this will return 0. + */ + virtual uint year() const = 0; + + /*! + * Returns the track number; if there is no track number set, this will + * return 0. + */ + virtual uint track() const = 0; + + /*! + * Sets the title to \a s. If \a s is String::null then this value will be + * cleared. + */ + virtual void setTitle(const String &s) = 0; + + /*! + * Sets the artist to \a s. If \a s is String::null then this value will be + * cleared. + */ + virtual void setArtist(const String &s) = 0; + + /*! + * Sets the album to \a s. If \a s is String::null then this value will be + * cleared. + */ + virtual void setAlbum(const String &s) = 0; + + /*! + * Sets the album to \a s. If \a s is String::null then this value will be + * cleared. + */ + virtual void setComment(const String &s) = 0; + + /*! + * Sets the genre to \a s. If \a s is String::null then this value will be + * cleared. For tag formats that use a fixed set of genres, the appropriate + * value will be selected based on a string comparison. A list of available + * genres for those formats should be available in that type's + * implementation. + */ + virtual void setGenre(const String &s) = 0; + + /*! + * Sets the year to \a i. If \a s is 0 then this value will be cleared. + */ + virtual void setYear(uint i) = 0; + + /*! + * Sets the track to \a i. If \a s is 0 then this value will be cleared. + */ + virtual void setTrack(uint i) = 0; + + /*! + * Returns true if the tag does not contain any data. This should be + * reimplemented in subclasses that provide more than the basic tagging + * abilities in this class. + */ + virtual bool isEmpty() const; + + /*! + * Copies the generic data from one tag to another. + * + * \note This will no affect any of the lower level details of the tag. For + * instance if any of the tag type specific data (maybe a URL for a band) is + * set, this will not modify or copy that. This just copies using the API + * in this class. + * + * If \a overwrite is true then the values will be unconditionally copied. + * If false only empty values will be overwritten. + */ + static void duplicate(const Tag *source, Tag *target, bool overwrite = true); + + protected: + /*! + * Construct a Tag. This is protected since tags should only be instantiated + * through subclasses. + */ + Tag(); + + private: + Tag(const Tag &); + Tag &operator=(const Tag &); + + class TagPrivate; + TagPrivate *d; + }; +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/taglib-config.in b/Libraries/TagLib/Files/taglib/taglib-config.in new file mode 100644 index 000000000..991abb856 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/taglib-config.in @@ -0,0 +1,55 @@ +#!/bin/sh + +usage() +{ + echo "usage: $0 [OPTIONS]" +cat << EOH + +options: + [--libs] + [--cflags] + [--version] + [--prefix] +EOH + exit 1; +} + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +flags="" + +if test $# -eq 0 ; then + usage +fi + +while test $# -gt 0 +do + case $1 in + --libs) + flags="$flags -L$libdir -ltag" + ;; + --cflags) + flags="$flags -I$includedir/taglib" + ;; + --version) + echo 1.3.1 + ;; + --prefix) + echo $prefix + ;; + *) + echo "$0: unknown option $1" + echo + usage + ;; + esac + shift +done + +if test -n "$flags" +then + echo $flags +fi diff --git a/Libraries/TagLib/Files/taglib/toolkit/Makefile.am b/Libraries/TagLib/Files/taglib/toolkit/Makefile.am new file mode 100644 index 000000000..287a9e9ad --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libtoolkit.la + +libtoolkit_la_SOURCES = \ + tstring.cpp tstringlist.cpp tbytevector.cpp \ + tbytevectorlist.cpp tfile.cpp tdebug.cpp unicode.cpp + +taglib_include_HEADERS = \ + taglib.h tstring.h tlist.h tlist.tcc tstringlist.h \ + tbytevector.h tbytevectorlist.h tfile.h tdebug.h \ + tmap.h tmap.tcc + +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libtoolkit_la_SOURCES) $(taglib_include_HEADERS) diff --git a/Libraries/TagLib/Files/taglib/toolkit/Makefile.in b/Libraries/TagLib/Files/taglib/toolkit/Makefile.in new file mode 100644 index 000000000..d6af16c9d --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/Makefile.in @@ -0,0 +1,572 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 3 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +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@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +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@ +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@ +link_zlib_FALSE = @link_zlib_FALSE@ +link_zlib_TRUE = @link_zlib_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libtoolkit.la + +libtoolkit_la_SOURCES = \ + tstring.cpp tstringlist.cpp tbytevector.cpp \ + tbytevectorlist.cpp tfile.cpp tdebug.cpp unicode.cpp + + +taglib_include_HEADERS = \ + taglib.h tstring.h tlist.h tlist.tcc tstringlist.h \ + tbytevector.h tbytevectorlist.h tfile.h tdebug.h \ + tmap.h tmap.tcc + + +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(libtoolkit_la_SOURCES) $(taglib_include_HEADERS) +subdir = taglib/toolkit +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libtoolkit_la_LDFLAGS = +libtoolkit_la_LIBADD = +am_libtoolkit_la_OBJECTS = tstring.lo tstringlist.lo tbytevector.lo \ + tbytevectorlist.lo tfile.lo tdebug.lo unicode.lo +#>- libtoolkit_la_OBJECTS = $(am_libtoolkit_la_OBJECTS) +#>+ 5 +libtoolkit_la_final_OBJECTS = libtoolkit_la.all_cpp.lo +libtoolkit_la_nofinal_OBJECTS = tstring.lo tstringlist.lo tbytevector.lo \ + tbytevectorlist.lo tfile.lo tdebug.lo unicode.lo +@KDE_USE_FINAL_FALSE@libtoolkit_la_OBJECTS = $(libtoolkit_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libtoolkit_la_OBJECTS = $(libtoolkit_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/tbytevector.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/tbytevectorlist.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/tdebug.Plo ./$(DEPDIR)/tfile.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/tstring.Plo ./$(DEPDIR)/tstringlist.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/unicode.Plo +#>+ 11 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libtoolkit_la.all_cpp.P ./$(DEPDIR)/tbytevector.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/tbytevectorlist.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/tdebug.Plo ./$(DEPDIR)/tfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/tstring.Plo ./$(DEPDIR)/tstringlist.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/unicode.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/tbytevector.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/tbytevectorlist.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/tdebug.Plo ./$(DEPDIR)/tfile.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/tstring.Plo ./$(DEPDIR)/tstringlist.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/unicode.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libtoolkit_la_SOURCES) +HEADERS = $(taglib_include_HEADERS) + +DIST_COMMON = $(taglib_include_HEADERS) Makefile.am Makefile.in +SOURCES = $(libtoolkit_la_SOURCES) + +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu taglib/toolkit/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/toolkit/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/toolkit/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libtoolkit.la: $(libtoolkit_la_OBJECTS) $(libtoolkit_la_DEPENDENCIES) + $(CXXLINK) $(libtoolkit_la_LDFLAGS) $(libtoolkit_la_OBJECTS) $(libtoolkit_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tbytevector.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tbytevectorlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tdebug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tstring.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tstringlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unicode.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +taglib_includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-taglib_includeHEADERS: $(taglib_include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f"; \ + $(taglib_includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +uninstall-taglib_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(taglib_include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(taglib_includedir)/$$f"; \ + rm -f $(DESTDIR)$(taglib_includedir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +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: $(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 "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +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 +#>- DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +#>+ 4 +KDE_DIST=unicode.h + +DISTFILES= $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) $(KDE_DIST) + + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +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"; \ + $(mkinstalldirs) "$(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 $(LTLIBRARIES) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(taglib_includedir) +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_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(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 +#>+ 1 +clean: kde-rpo-clean clean-am + +#>- clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-taglib_includeHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +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 uninstall-taglib_includeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-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 install-taglib_includeHEADERS \ + 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 \ + uninstall-taglib_includeHEADERS + +# 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: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu taglib/toolkit/Makefile + cd $(top_srcdir) && perl admin/am_edit taglib/toolkit/Makefile.in + + +#>+ 11 +libtoolkit_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/tstring.cpp $(srcdir)/tstringlist.cpp $(srcdir)/tbytevector.cpp $(srcdir)/tbytevectorlist.cpp $(srcdir)/tfile.cpp $(srcdir)/tdebug.cpp $(srcdir)/unicode.cpp + @echo 'creating libtoolkit_la.all_cpp.cpp ...'; \ + rm -f libtoolkit_la.all_cpp.files libtoolkit_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libtoolkit_la.all_cpp.final; \ + for file in tstring.cpp tstringlist.cpp tbytevector.cpp tbytevectorlist.cpp tfile.cpp tdebug.cpp unicode.cpp ; do \ + echo "#include \"$$file\"" >> libtoolkit_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libtoolkit_la.all_cpp.final; \ + done; \ + cat libtoolkit_la.all_cpp.final libtoolkit_la.all_cpp.files > libtoolkit_la.all_cpp.cpp; \ + rm -f libtoolkit_la.all_cpp.final libtoolkit_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libtoolkit_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libtoolkit_la_OBJECTS="$(libtoolkit_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libtoolkit_la_OBJECTS="$(libtoolkit_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libtoolkit_la_OBJECTS="$(libtoolkit_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libtoolkit_la_OBJECTS="$(libtoolkit_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/Libraries/TagLib/Files/taglib/toolkit/taglib.h b/Libraries/TagLib/Files/taglib/toolkit/taglib.h new file mode 100644 index 000000000..a32407ecb --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/taglib.h @@ -0,0 +1,155 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_H +#define TAGLIB_H + +#define TAGLIB_MAJOR_VERSION 1 +#define TAGLIB_MINOR_VERSION 3 +#define TAGLIB_PATCH_VERSION 1 + +#include + +//! A namespace for all TagLib related classes and functions + +/*! + * This namespace contains everything in TagLib. For projects working with + * TagLib extensively it may be conveniten to add a + * \code + * using namespace TagLib; + * \endcode + */ + +namespace TagLib { + + class String; + + typedef wchar_t wchar; + typedef unsigned char uchar; + typedef unsigned int uint; + typedef unsigned long ulong; + + /*! + * Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3) + * so I'm providing something here that should be constant. + */ + typedef std::basic_string wstring; + +#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. + /*! + * \internal + * This is just used as a base class for shared classes in TagLib. + * + * \warning This is not part of the TagLib public API! + */ + + class RefCounter + { + public: + RefCounter() : refCount(1) {} + void ref() { refCount++; } + bool deref() { return ! --refCount ; } + int count() { return refCount; } + private: + uint refCount; + }; + +#endif // DO_NOT_DOCUMENT + +} + +/*! + * \mainpage TagLib + * \section intro Introduction + * TagLib, is well, a library for reading and editing audio meta data, commonly know as \e tags. + * + * Some goals of TagLib: + * - A clean, high level, C++ API to handling audio meta data. + * - Support for at least ID3v1, ID3v2 and Ogg Vorbis \e comments. + * - A generic, \e simple API for the most common tagging related functions. + * - Binary compatibility between minor releases using the standard KDE/Qt techniques for C++ binary compatibility. + * - Make the tagging framework extensible by library users; i.e. it will be possible for libarary users to implement + * additional ID3v2 frames, without modifying the TagLib source (through the use of Abstract Factories and + * such. + * + * Because TagLib desires to be toolkit agnostic, in hope of being widely adopted and the most flexible in licensing + * TagLib provides many of its own toolkit classes; in fact the only external dependancy that TagLib has, it a + * semi-sane STL implementation. + * + * \section why Why TagLib? + * + * TagLib was written to fill a gap in the Open Source/Free Software community. Currently there is a lack in the + * OSS/FS for a homogenous API to the most common music types. + * + * As TagLib will be initially injected into the KDE community, while I am not linking to any of the KDE or Qt libraries + * I have tried to follow the coding style of those libraries. Again, this is in sharp contrast to id3lib, which + * basically provides a hybrid C/C++ API and uses a dubious object model. + * + * I get asked rather frequently why I am replacing id3lib (mostly by people that have never worked with id3lib), if + * you are concerned about this please email me; I can provide my lengthy standard rant. :-) + * + * \section examples Examples: + * + * I've talked a lot about the \e homogenous API to common music formats. Here's an example of how things (will) work: + * + * \code + * + * TagLib::FileRef f("Latex Solar Beef.mp3"); + * TagLib::String artist = f.tag()->artist(); // artist == "Frank Zappa" + * + * f.tag()->setAlbum("Fillmore East"); + * f.save(); + * + * TagLib::FileRef g("Free City Rhymes.ogg"); + * TagLib::String album = g.tag()->album(); // album == "NYC Ghosts & Flowers" + * + * g.tag()->setTrack(1); + * g.save(); + * + * \endcode + * + * Note that these high level functions work for Ogg, FLAC, MPC \e and MP3 (or any other formats supported in the + * future). For this high level API, which is suitable for most applications, the differences between tag and file + * formats can all be ignored. + * + * \section Building + * + * TagLib provides a script called taglib-config that returns the necessary compiler and linker flags, as well as the + * version number. To build a small sample program one would use: + * + * g++ taglib-test.cpp `taglib-config --cflags --libs` -o taglib-test + * + * This should generally be integrated into the configure check for TagLib in your project. + * + * \note TagLib includes assume that you have the TagLib include path specified in the compile line, by default + * -I/usr/local/include/taglib. Using #include will not work. (Though this + * is usually handled by the taglib-config script mentioned above.) + * + * \section Contact + * + * - TagLib Homepage + * - TagLib Mailing List (taglib-devel@kde.org) + * + * \author Scott Wheeler + * + */ + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tbytevector.cpp b/Libraries/TagLib/Files/taglib/toolkit/tbytevector.cpp new file mode 100644 index 000000000..de4ca6f9f --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tbytevector.cpp @@ -0,0 +1,627 @@ +/*************************************************************************** + copyright : (C) 2002 - 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include +#include + +#include "tbytevector.h" + +// This is a bit ugly to keep writing over and over again. + +// A rather obscure feature of the C++ spec that I hadn't thought of that makes +// working with C libs much more effecient. There's more here: +// +// http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp + +#define DATA(x) (&(x->data[0])) + +namespace TagLib { + static const uint crcTable[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 + }; + + /*! + * A templatized find that works both with a ByteVector and a ByteVectorMirror. + */ + + template + int vectorFind(const Vector &v, const Vector &pattern, uint offset, int byteAlign) + { + if(pattern.size() > v.size() || offset >= v.size() - 1) + return -1; + + // if an offset was specified, just do a recursive call on the substring + + if(offset > 0) { + + // start at the next byte aligned block + + Vector section = v.mid(offset + byteAlign - 1 - offset % byteAlign); + int match = section.find(pattern, 0, byteAlign); + return match >= 0 ? int(match + offset) : -1; + } + + // this is a simplified Boyer-Moore string searching algorithm + + uchar lastOccurrence[256]; + + + for(uint i = 0; i < 256; ++i) + lastOccurrence[i] = uchar(pattern.size()); + + for(uint i = 0; i < pattern.size() - 1; ++i) + lastOccurrence[unsigned(pattern[i])] = uchar(pattern.size() - i - 1); + + for(uint i = pattern.size() - 1; i < v.size(); i += lastOccurrence[uchar(v.at(i))]) { + int iBuffer = i; + int iPattern = pattern.size() - 1; + + while(iPattern >= 0 && v.at(iBuffer) == pattern[iPattern]) { + --iBuffer; + --iPattern; + } + + if(-1 == iPattern && (iBuffer + 1) % byteAlign == 0) + return iBuffer + 1; + } + + return -1; + } + + /*! + * Wraps the accessors to a ByteVector to make the search algorithm access the + * elements in reverse. + * + * \see vectorFind() + * \see ByteVector::rfind() + */ + + class ByteVectorMirror + { + public: + ByteVectorMirror(const ByteVector &source) : v(source) {} + const char operator[](int index) const + { + return v[v.size() - index - 1]; + } + + const char at(int index) const + { + return v.at(v.size() - index - 1); + } + + ByteVectorMirror mid(uint index, uint length = 0xffffffff) const + { + return length == 0xffffffff ? v.mid(0, index) : v.mid(index - length, length); + } + + uint size() const + { + return v.size(); + } + + int find(const ByteVectorMirror &pattern, uint offset = 0, int byteAlign = 1) const + { + ByteVectorMirror v(*this); + + const int pos = vectorFind(v, pattern, offset, byteAlign); + + // If the offset is zero then we need to adjust the location in the search + // to be appropriately reversed. If not we need to account for the fact + // that the recursive call (called from the above line) has already ajusted + // for this but that the normal templatized find above will add the offset + // to the returned value. + // + // This is a little confusing at first if you don't first stop to think + // through the logic involved in the forward search. + + if(pos == -1) + return -1; + + if(offset == 0) + return size() - pos - pattern.size(); + else + return pos - offset; + } + + private: + const ByteVector v; + }; + + template + T toNumber(const std::vector &data, bool mostSignificantByteFirst) + { + T sum = 0; + + if(data.size() <= 0) { + debug("ByteVectorMirror::toNumber() -- data is empty, returning 0"); + return sum; + } + + uint size = sizeof(T); + uint last = data.size() > size ? size - 1 : data.size() - 1; + + for(uint i = 0; i <= last; i++) + sum |= (T) uchar(data[i]) << ((mostSignificantByteFirst ? last - i : i) * 8); + + return sum; + } + + template + ByteVector fromNumber(T value, bool mostSignificantByteFirst) + { + int size = sizeof(T); + + ByteVector v(size, 0); + + for(int i = 0; i < size; i++) + v[i] = uchar(value >> ((mostSignificantByteFirst ? size - 1 - i : i) * 8) & 0xff); + + return v; + } +} + +using namespace TagLib; + +class ByteVector::ByteVectorPrivate : public RefCounter +{ +public: + ByteVectorPrivate() : RefCounter(), size(0) {} + ByteVectorPrivate(const std::vector &v) : RefCounter(), data(v), size(v.size()) {} + ByteVectorPrivate(TagLib::uint len, char value) : RefCounter(), data(len, value), size(len) {} + + std::vector data; + + // std::vector::size() is very slow, so we'll cache the value + + uint size; +}; + +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +ByteVector ByteVector::null; + +ByteVector ByteVector::fromCString(const char *s, uint length) +{ + ByteVector v; + + if(length == 0xffffffff) + v.setData(s); + else + v.setData(s, length); + + return v; +} + +ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) +{ + return fromNumber(value, mostSignificantByteFirst); +} + +ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) +{ + return fromNumber(value, mostSignificantByteFirst); +} + +ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) +{ + return fromNumber(value, mostSignificantByteFirst); +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +ByteVector::ByteVector() +{ + d = new ByteVectorPrivate; +} + +ByteVector::ByteVector(uint size, char value) +{ + d = new ByteVectorPrivate(size, value); +} + +ByteVector::ByteVector(const ByteVector &v) : d(v.d) +{ + d->ref(); +} + +ByteVector::ByteVector(char c) +{ + d = new ByteVectorPrivate; + d->data.push_back(c); + d->size = 1; +} + +ByteVector::ByteVector(const char *data, uint length) +{ + d = new ByteVectorPrivate; + setData(data, length); +} + +ByteVector::ByteVector(const char *data) +{ + d = new ByteVectorPrivate; + setData(data); +} + +ByteVector::~ByteVector() +{ + if(d->deref()) + delete d; +} + +void ByteVector::setData(const char *data, uint length) +{ + detach(); + + resize(length); + ::memcpy(DATA(d), data, length); +} + +void ByteVector::setData(const char *data) +{ + setData(data, ::strlen(data)); +} + +char *ByteVector::data() +{ + detach(); + return DATA(d); +} + +const char *ByteVector::data() const +{ + return DATA(d); +} + +ByteVector ByteVector::mid(uint index, uint length) const +{ + ByteVector v; + + ConstIterator endIt; + + if(length < 0xffffffff && length + index < size()) + endIt = d->data.begin() + index + length; + else + endIt = d->data.end(); + + v.d->data.insert(v.d->data.begin(), ConstIterator(d->data.begin() + index), endIt); + v.d->size = v.d->data.size(); + + return v; +} + +char ByteVector::at(uint index) const +{ + return index < size() ? d->data[index] : 0; +} + +int ByteVector::find(const ByteVector &pattern, uint offset, int byteAlign) const +{ + return vectorFind(*this, pattern, offset, byteAlign); +} + +int ByteVector::rfind(const ByteVector &pattern, uint offset, int byteAlign) const +{ + // Ok, this is a little goofy, but pretty cool after it sinks in. Instead of + // reversing the find method's Boyer-Moore search algorithm I created a "mirror" + // for a ByteVector to reverse the behavior of the accessors. + + ByteVectorMirror v(*this); + ByteVectorMirror p(pattern); + + return v.find(p, offset, byteAlign); +} + +bool ByteVector::containsAt(const ByteVector &pattern, uint offset, uint patternOffset, uint patternLength) const +{ + if(pattern.size() < patternLength) + patternLength = pattern.size(); + + // do some sanity checking -- all of these things are needed for the search to be valid + + if(patternLength > size() || offset >= size() || patternOffset >= pattern.size() || patternLength == 0) + return false; + + // loop through looking for a mismatch + + for(uint i = 0; i < patternLength - patternOffset; i++) { + if(at(i + offset) != pattern[i + patternOffset]) + return false; + } + + return true; +} + +bool ByteVector::startsWith(const ByteVector &pattern) const +{ + return containsAt(pattern, 0); +} + +bool ByteVector::endsWith(const ByteVector &pattern) const +{ + return containsAt(pattern, size() - pattern.size()); +} + +int ByteVector::endsWithPartialMatch(const ByteVector &pattern) const +{ + if(pattern.size() > size()) + return -1; + + const int startIndex = size() - pattern.size(); + + // try to match the last n-1 bytes from the vector (where n is the pattern + // size) -- continue trying to match n-2, n-3...1 bytes + + for(uint i = 1; i < pattern.size(); i++) { + if(containsAt(pattern, startIndex + i, 0, pattern.size() - i)) + return startIndex + i; + } + + return -1; +} + +void ByteVector::append(const ByteVector &v) +{ + detach(); + + uint originalSize = d->size; + resize(d->size + v.d->size); + ::memcpy(DATA(d) + originalSize, DATA(v.d), v.size()); +} + +void ByteVector::clear() +{ + detach(); + d->data.clear(); +} + +TagLib::uint ByteVector::size() const +{ + return d->size; +} + +ByteVector &ByteVector::resize(uint size, char padding) +{ + if(d->size < size) { + d->data.reserve(size); + d->data.insert(d->data.end(), size - d->size, padding); + } + else + d->data.erase(d->data.begin() + size, d->data.end()); + + d->size = size; + + return *this; +} + +ByteVector::Iterator ByteVector::begin() +{ + return d->data.begin(); +} + +ByteVector::ConstIterator ByteVector::begin() const +{ + return d->data.begin(); +} + +ByteVector::Iterator ByteVector::end() +{ + return d->data.end(); +} + +ByteVector::ConstIterator ByteVector::end() const +{ + return d->data.end(); +} + +bool ByteVector::isNull() const +{ + return d == null.d; +} + +bool ByteVector::isEmpty() const +{ + return d->data.size() == 0; +} + +TagLib::uint ByteVector::checksum() const +{ + uint sum = 0; + for(ByteVector::ConstIterator it = begin(); it != end(); ++it) + sum = (sum << 8) ^ crcTable[((sum >> 24) & 0xff) ^ uchar(*it)]; + return sum; +} + +TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const +{ + return toNumber(d->data, mostSignificantByteFirst); +} + +short ByteVector::toShort(bool mostSignificantByteFirst) const +{ + return toNumber(d->data, mostSignificantByteFirst); +} + +long long ByteVector::toLongLong(bool mostSignificantByteFirst) const +{ + return toNumber(d->data, mostSignificantByteFirst); +} + +const char &ByteVector::operator[](int index) const +{ + return d->data[index]; +} + +char &ByteVector::operator[](int index) +{ + detach(); + + return d->data[index]; +} + +bool ByteVector::operator==(const ByteVector &v) const +{ + if(d->size != v.d->size) + return false; + + return ::memcmp(data(), v.data(), size()) == 0; +} + +bool ByteVector::operator!=(const ByteVector &v) const +{ + return !operator==(v); +} + +bool ByteVector::operator==(const char *s) const +{ + if(d->size != ::strlen(s)) + return false; + + return ::memcmp(data(), s, d->size) == 0; +} + +bool ByteVector::operator!=(const char *s) const +{ + return !operator==(s); +} + +bool ByteVector::operator<(const ByteVector &v) const +{ + int result = ::memcmp(data(), v.data(), d->size < v.d->size ? d->size : v.d->size); + + if(result != 0) + return result < 0; + else + return size() < v.size(); +} + +bool ByteVector::operator>(const ByteVector &v) const +{ + return v < *this; +} + +ByteVector ByteVector::operator+(const ByteVector &v) const +{ + ByteVector sum(*this); + sum.append(v); + return sum; +} + +ByteVector &ByteVector::operator=(const ByteVector &v) +{ + if(&v == this) + return *this; + + if(d->deref()) + delete d; + + d = v.d; + d->ref(); + return *this; +} + +ByteVector &ByteVector::operator=(char c) +{ + if(d->deref()) + delete d; + *this = ByteVector(c); + return *this; +} + +ByteVector &ByteVector::operator=(const char *data) +{ + if(d->deref()) + delete d; + *this = ByteVector(data); + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void ByteVector::detach() +{ + if(d->count() > 1) { + d->deref(); + d = new ByteVectorPrivate(d->data); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// related functions +//////////////////////////////////////////////////////////////////////////////// + +std::ostream &operator<<(std::ostream &s, const ByteVector &v) +{ + for(TagLib::uint i = 0; i < v.size(); i++) + s << v[i]; + return s; +} diff --git a/Libraries/TagLib/Files/taglib/toolkit/tbytevector.h b/Libraries/TagLib/Files/taglib/toolkit/tbytevector.h new file mode 100644 index 000000000..b7d88f41e --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tbytevector.h @@ -0,0 +1,397 @@ +/*************************************************************************** + copyright : (C) 2002 - 2004 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_BYTEVECTOR_H +#define TAGLIB_BYTEVECTOR_H + +#include "taglib.h" + +#include + +namespace TagLib { + + //! A byte vector + + /*! + * This class provides a byte vector with some methods that are useful for + * tagging purposes. Many of the search functions are tailored to what is + * useful for finding tag related paterns in a data array. + */ + + class ByteVector + { + public: +#ifndef DO_NOT_DOCUMENT + typedef std::vector::iterator Iterator; + typedef std::vector::const_iterator ConstIterator; +#endif + + /*! + * Constructs an empty byte vector. + */ + ByteVector(); + + /*! + * Construct a vector of size \a size with all values set to \a value by + * default. + */ + ByteVector(uint size, char value = 0); + + /*! + * Contructs a byte vector that is a copy of \a v. + */ + ByteVector(const ByteVector &v); + + /*! + * Contructs a byte vector that contains \a c. + */ + ByteVector(char c); + + /*! + * Constructs a byte vector that copies \a data for up to \a length bytes. + */ + ByteVector(const char *data, uint length); + + /*! + * Constructs a byte vector that copies \a data up to the first null + * byte. The behavior is undefined if \a data is not null terminated. + * This is particularly useful for constructing byte arrays from string + * constants. + */ + ByteVector(const char *data); + + /*! + * Destroys this ByteVector instance. + */ + virtual ~ByteVector(); + + /*! + * Sets the data for the byte array using the first \a length bytes of \a data + */ + void setData(const char *data, uint length); + + /*! + * Sets the data for the byte array copies \a data up to the first null + * byte. The behavior is undefined if \a data is not null terminated. + */ + void setData(const char *data); + + /*! + * Returns a pointer to the internal data structure. + * + * \warning Care should be taken when modifying this data structure as it is + * easy to corrupt the ByteVector when doing so. Specifically, while the + * data may be changed, its length may not be. + */ + char *data(); + + /*! + * Returns a pointer to the internal data structure which may not be modified. + */ + const char *data() const; + + /*! + * Returns a byte vector made up of the bytes starting at \a index and + * for \a length bytes. If \a length is not specified it will return the bytes + * from \a index to the end of the vector. + */ + ByteVector mid(uint index, uint length = 0xffffffff) const; + + /*! + * This essentially performs the same as operator[](), but instead of causing + * a runtime error if the index is out of bounds, it will return a null byte. + */ + char at(uint index) const; + + /*! + * Searches the ByteVector for \a pattern starting at \a offset and returns + * the offset. Returns -1 if the pattern was not found. If \a byteAlign is + * specified the pattern will only be matched if it starts on a byteDivisible + * by \a byteAlign. + */ + int find(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; + + /*! + * Searches the ByteVector for \a pattern starting from either the end of the + * vector or \a offset and returns the offset. Returns -1 if the pattern was + * not found. If \a byteAlign is specified the pattern will only be matched + * if it starts on a byteDivisible by \a byteAlign. + */ + int rfind(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; + + /*! + * Checks to see if the vector contains the \a pattern starting at position + * \a offset. Optionally, if you only want to search for part of the pattern + * you can specify an offset within the pattern to start from. Also, you can + * specify to only check for the first \a patternLength bytes of \a pattern with + * the \a patternLength argument. + */ + bool containsAt(const ByteVector &pattern, uint offset, uint patternOffset = 0, uint patternLength = 0xffffffff) const; + + /*! + * Returns true if the vector starts with \a pattern. + */ + bool startsWith(const ByteVector &pattern) const; + + /*! + * Returns true if the vector ends with \a pattern. + */ + bool endsWith(const ByteVector &pattern) const; + + /*! + * Checks for a partial match of \a pattern at the end of the vector. It + * returns the offset of the partial match within the vector, or -1 if the + * pattern is not found. This method is particularly useful when searching for + * patterns that start in one vector and end in another. When combined with + * startsWith() it can be used to find a pattern that overlaps two buffers. + * + * \note This will not match the complete pattern at the end of the string; use + * endsWith() for that. + */ + int endsWithPartialMatch(const ByteVector &pattern) const; + + /*! + * Appends \a v to the end of the ByteVector. + */ + void append(const ByteVector &v); + + /*! + * Clears the data. + */ + void clear(); + + /*! + * Returns the size of the array. + */ + uint size() const; + + /*! + * Resize the vector to \a size. If the vector is currently less than + * \a size, pad the remaining spaces with \a padding. Returns a reference + * to the resized vector. + */ + ByteVector &resize(uint size, char padding = 0); + + /*! + * Returns an Iterator that points to the front of the vector. + */ + Iterator begin(); + + /*! + * Returns a ConstIterator that points to the front of the vector. + */ + ConstIterator begin() const; + + /*! + * Returns an Iterator that points to the back of the vector. + */ + Iterator end(); + + /*! + * Returns a ConstIterator that points to the back of the vector. + */ + ConstIterator end() const; + + /*! + * Returns true if the vector is null. + * + * \note A vector may be empty without being null. + * \see isEmpty() + */ + bool isNull() const; + + /*! + * Returns true if the ByteVector is empty. + * + * \see size() + * \see isNull() + */ + bool isEmpty() const; + + /*! + * Returns a CRC checksum of the byte vector's data. + */ + uint checksum() const; + + /*! + * Converts the first 4 bytes of the vector to an unsigned integer. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == + * 0x01000000 == 1. + * + * \see fromUInt() + */ + uint toUInt(bool mostSignificantByteFirst = true) const; + + /*! + * Converts the first 2 bytes of the vector to a short. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. + * + * \see fromShort() + */ + short toShort(bool mostSignificantByteFirst = true) const; + + /*! + * Converts the first 8 bytes of the vector to a (signed) long long. + * + * If \a mostSignificantByteFirst is true this will operate left to right + * evaluating the integer. For example if \a mostSignificantByteFirst is + * true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1, + * if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. + * + * \see fromUInt() + */ + long long toLongLong(bool mostSignificantByteFirst = true) const; + + /*! + * Creates a 4 byte ByteVector based on \a value. If + * \a mostSignificantByteFirst is true, then this will operate left to right + * in building the ByteVector. For example if \a mostSignificantByteFirst is + * true then $00 00 00 01 == 0x00000001 == 1, if false, $01 00 00 00 == + * 0x01000000 == 1. + * + * \see toUInt() + */ + static ByteVector fromUInt(uint value, bool mostSignificantByteFirst = true); + + /*! + * Creates a 2 byte ByteVector based on \a value. If + * \a mostSignificantByteFirst is true, then this will operate left to right + * in building the ByteVector. For example if \a mostSignificantByteFirst is + * true then $00 01 == 0x0001 == 1, if false, $01 00 == 0x0100 == 1. + * + * \see toShort() + */ + static ByteVector fromShort(short value, bool mostSignificantByteFirst = true); + + /*! + * Creates a 8 byte ByteVector based on \a value. If + * \a mostSignificantByteFirst is true, then this will operate left to right + * in building the ByteVector. For example if \a mostSignificantByteFirst is + * true then $00 00 00 01 == 0x0000000000000001 == 1, if false, + * $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. + * + * \see toLongLong() + */ + static ByteVector fromLongLong(long long value, bool mostSignificantByteFirst = true); + + /*! + * Returns a ByteVector based on the CString \a s. + */ + static ByteVector fromCString(const char *s, uint length = 0xffffffff); + + /*! + * Returns a const refernence to the byte at \a index. + */ + const char &operator[](int index) const; + + /*! + * Returns a reference to the byte at \a index. + */ + char &operator[](int index); + + /*! + * Returns true if this ByteVector and \a v are equal. + */ + bool operator==(const ByteVector &v) const; + + /*! + * Returns true if this ByteVector and \a v are not equal. + */ + bool operator!=(const ByteVector &v) const; + + /*! + * Returns true if this ByteVector and the null terminated C string \a s + * contain the same data. + */ + bool operator==(const char *s) const; + + /*! + * Returns true if this ByteVector and the null terminated C string \a s + * do not contain the same data. + */ + bool operator!=(const char *s) const; + + /*! + * Returns true if this ByteVector is less than \a v. The value of the + * vectors is determined by evaluating the character from left to right, and + * in the event one vector is a superset of the other, the size is used. + */ + bool operator<(const ByteVector &v) const; + + /*! + * Returns true if this ByteVector is greater than \a v. + */ + bool operator>(const ByteVector &v) const; + + /*! + * Returns a vector that is \a v appended to this vector. + */ + ByteVector operator+(const ByteVector &v) const; + + /*! + * Copies ByteVector \a v. + */ + ByteVector &operator=(const ByteVector &v); + + /*! + * Copies ByteVector \a v. + */ + ByteVector &operator=(char c); + + /*! + * Copies ByteVector \a v. + */ + ByteVector &operator=(const char *data); + + /*! + * A static, empty ByteVector which is convenient and fast (since returning + * an empty or "null" value does not require instantiating a new ByteVector). + */ + static ByteVector null; + + protected: + /* + * If this ByteVector is being shared via implicit sharing, do a deep copy + * of the data and separate from the shared members. This should be called + * by all non-const subclass members. + */ + void detach(); + + private: + class ByteVectorPrivate; + ByteVectorPrivate *d; + }; + +} + +/*! + * \relates TagLib::ByteVector + * Streams the ByteVector \a v to the output stream \a s. + */ +std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v); + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tbytevectorlist.cpp b/Libraries/TagLib/Files/taglib/toolkit/tbytevectorlist.cpp new file mode 100644 index 000000000..3799f5e7a --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tbytevectorlist.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "tbytevectorlist.h" + +using namespace TagLib; + +class ByteVectorListPrivate +{ + +}; + +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, + int byteAlign) +{ + ByteVectorList l; + + uint previousOffset = 0; + for(int offset = v.find(pattern, 0, byteAlign); + offset != -1; + offset = v.find(pattern, offset + pattern.size(), byteAlign)) + { + l.append(v.mid(previousOffset, offset - previousOffset)); + previousOffset = offset + pattern.size(); + } + + if(previousOffset < v.size()) + l.append(v.mid(previousOffset, v.size() - previousOffset)); + + return l; +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +ByteVectorList::ByteVectorList() : List() +{ + +} + +ByteVectorList::ByteVectorList(const ByteVectorList &l) : List(l) +{ + +} + +ByteVectorList::~ByteVectorList() +{ + +} + +ByteVector ByteVectorList::toByteVector(const ByteVector &separator) const +{ + ByteVector v; + + ConstIterator it = begin(); + + while(it != end()) { + v.append(*it); + it++; + if(it != end()) + v.append(separator); + } + + return v; +} diff --git a/Libraries/TagLib/Files/taglib/toolkit/tbytevectorlist.h b/Libraries/TagLib/Files/taglib/toolkit/tbytevectorlist.h new file mode 100644 index 000000000..ab5e2d625 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tbytevectorlist.h @@ -0,0 +1,77 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_BYTEVECTORLIST_H +#define TAGLIB_BYTEVECTORLIST_H + +#include "tbytevector.h" +#include "tlist.h" + +namespace TagLib { + + //! A list of ByteVectors + + /*! + * A List specialization with some handy features useful for ByteVectors. + */ + + class ByteVectorList : public List + { + public: + + /*! + * Construct an empty ByteVectorList. + */ + ByteVectorList(); + + /*! + * Destroys this ByteVectorList instance. + */ + virtual ~ByteVectorList(); + + /*! + * Make a shallow, implicitly shared, copy of \a l. Because this is + * implicitly shared, this method is lightweight and suitable for + * pass-by-value usage. + */ + ByteVectorList(const ByteVectorList &l); + + /*! + * Convert the ByteVectorList to a ByteVector separated by \a separator. By + * default a space is used. + */ + ByteVector toByteVector(const ByteVector &separator = " ") const; + + /*! + * Splits the ByteVector \a v into several strings at \a pattern. This will + * not include the pattern in the returned ByteVectors. + */ + static ByteVectorList split(const ByteVector &v, const ByteVector &pattern, + int byteAlign = 1); + + private: + class ByteVectorListPrivate; + ByteVectorListPrivate *d; + }; + +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tdebug.cpp b/Libraries/TagLib/Files/taglib/toolkit/tdebug.cpp new file mode 100644 index 000000000..4b3b40e8a --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tdebug.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include + +#include "tdebug.h" +#include "tstring.h" + +using namespace TagLib; + +#ifndef NDEBUG +void TagLib::debug(const String &s) +{ + std::cerr << "TagLib: " << s << std::endl; +} + +void TagLib::debugData(const ByteVector &v) +{ + for(uint i = 0; i < v.size(); i++) { + + std::cout << "*** [" << i << "] - '" << char(v[i]) << "' - int " << int(v[i]) + << std::endl; + + std::bitset<8> b(v[i]); + + for(int j = 0; j < 8; j++) + std::cout << i << ":" << j << " " << b.test(j) << std::endl; + + std::cout << std::endl; + } +} +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tdebug.h b/Libraries/TagLib/Files/taglib/toolkit/tdebug.h new file mode 100644 index 000000000..fe7838ae0 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tdebug.h @@ -0,0 +1,67 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_DEBUG_H +#define TAGLIB_DEBUG_H + +namespace TagLib { + + class String; + class ByteVector; + +#ifndef DO_NOT_DOCUMENT +#ifndef NDEBUG + + /*! + * A simple function that prints debugging output to cerr if debugging is + * not disabled. + * + * \warning Do not use this outside of TagLib, it could lead to undefined + * symbols in your build if TagLib is built with NDEBUG defined and your + * application is not. + * + * \internal + */ + void debug(const String &s); + + /*! + * For debugging binary data. + * + * \warning Do not use this outside of TagLib, it could lead to undefined + * symbols in your build if TagLib is built with NDEBUG defined and your + * application is not. + * + * \internal + */ + void debugData(const ByteVector &v); + +#else + + // Define these to an empty statement if debugging is disabled. + +#define debug(x) +#define debugData(x) + +#endif +#endif +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tfile.cpp b/Libraries/TagLib/Files/taglib/toolkit/tfile.cpp new file mode 100644 index 000000000..5d8f1c987 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tfile.cpp @@ -0,0 +1,485 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "tfile.h" +#include "tstring.h" +#include "tdebug.h" + +#include +#include +#include + +using namespace TagLib; + +class File::FilePrivate +{ +public: + FilePrivate(const char *fileName) : + file(0), + name(fileName), + readOnly(true), + valid(true) + {} + + ~FilePrivate() + { + free((void *)name); + } + + FILE *file; + const char *name; + bool readOnly; + bool valid; + static const uint bufferSize = 1024; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +File::File(const char *file) +{ + d = new FilePrivate(::strdup(file)); + + d->readOnly = !isWritable(file); +// d->file = fopen(file, d->readOnly ? "r" : "r+"); + d->file = fopen(file, "r"); + + if(!d->file) + debug("Could not open file " + String(file)); +} + +File::~File() +{ + if(d->file) + fclose(d->file); + delete d; +} + +const char *File::name() const +{ + return d->name; +} + +ByteVector File::readBlock(ulong length) +{ + if(!d->file) { + debug("File::readBlock() -- Invalid File"); + return ByteVector::null; + } + + ByteVector v(static_cast(length)); + const int count = fread(v.data(), sizeof(char), length, d->file); + v.resize(count); + return v; +} + +void File::writeBlock(const ByteVector &data) +{ + if(!d->file) + return; + + if(d->readOnly) { + debug("File::writeBlock() -- attempted to write to a file that is not writable"); + return; + } + + fwrite(data.data(), sizeof(char), data.size(), d->file); +} + +long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before) +{ + if(!d->file || pattern.size() > d->bufferSize) + return -1; + + // The position in the file that the current buffer starts at. + + long bufferOffset = fromOffset; + ByteVector buffer; + + // These variables are used to keep track of a partial match that happens at + // the end of a buffer. + + int previousPartialMatch = -1; + int beforePreviousPartialMatch = -1; + + // Save the location of the current read pointer. We will restore the + // position using seek() before all returns. + + long originalPosition = tell(); + + // Start the search at the offset. + + seek(fromOffset); + + // This loop is the crux of the find method. There are three cases that we + // want to account for: + // + // (1) The previously searched buffer contained a partial match of the search + // pattern and we want to see if the next one starts with the remainder of + // that pattern. + // + // (2) The search pattern is wholly contained within the current buffer. + // + // (3) The current buffer ends with a partial match of the pattern. We will + // note this for use in the next itteration, where we will check for the rest + // of the pattern. + // + // All three of these are done in two steps. First we check for the pattern + // and do things appropriately if a match (or partial match) is found. We + // then check for "before". The order is important because it gives priority + // to "real" matches. + + for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) { + + // (1) previous partial match + + if(previousPartialMatch >= 0 && int(d->bufferSize) > previousPartialMatch) { + const int patternOffset = (d->bufferSize - previousPartialMatch); + if(buffer.containsAt(pattern, 0, patternOffset)) { + seek(originalPosition); + return bufferOffset - d->bufferSize + previousPartialMatch; + } + } + + if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(d->bufferSize) > beforePreviousPartialMatch) { + const int beforeOffset = (d->bufferSize - beforePreviousPartialMatch); + if(buffer.containsAt(before, 0, beforeOffset)) { + seek(originalPosition); + return -1; + } + } + + // (2) pattern contained in current buffer + + long location = buffer.find(pattern); + if(location >= 0) { + seek(originalPosition); + return bufferOffset + location; + } + + if(!before.isNull() && buffer.find(before) >= 0) { + seek(originalPosition); + return -1; + } + + // (3) partial match + + previousPartialMatch = buffer.endsWithPartialMatch(pattern); + + if(!before.isNull()) + beforePreviousPartialMatch = buffer.endsWithPartialMatch(before); + + bufferOffset += d->bufferSize; + } + + // Since we hit the end of the file, reset the status before continuing. + + clear(); + + seek(originalPosition); + + return -1; +} + + +long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before) +{ + if(!d->file || pattern.size() > d->bufferSize) + return -1; + + // The position in the file that the current buffer starts at. + + ByteVector buffer; + + // These variables are used to keep track of a partial match that happens at + // the end of a buffer. + + /* + int previousPartialMatch = -1; + int beforePreviousPartialMatch = -1; + */ + + // Save the location of the current read pointer. We will restore the + // position using seek() before all returns. + + long originalPosition = tell(); + + // Start the search at the offset. + + long bufferOffset; + if(fromOffset == 0) { + seek(-1 * int(d->bufferSize), End); + bufferOffset = tell(); + } + else { + seek(fromOffset + -1 * int(d->bufferSize), Beginning); + bufferOffset = tell(); + } + + // See the notes in find() for an explanation of this algorithm. + + for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) { + + // TODO: (1) previous partial match + + // (2) pattern contained in current buffer + + long location = buffer.rfind(pattern); + if(location >= 0) { + seek(originalPosition); + return bufferOffset + location; + } + + if(!before.isNull() && buffer.find(before) >= 0) { + seek(originalPosition); + return -1; + } + + // TODO: (3) partial match + + bufferOffset -= d->bufferSize; + seek(bufferOffset); + } + + // Since we hit the end of the file, reset the status before continuing. + + clear(); + + seek(originalPosition); + + return -1; +} + +void File::insert(const ByteVector &data, ulong start, ulong replace) +{ + if(!d->file) + return; + + if(data.size() == replace) { + seek(start); + writeBlock(data); + return; + } + else if(data.size() < replace) { + seek(start); + writeBlock(data); + removeBlock(start + data.size(), replace - data.size()); + return; + } + + // Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore + // and avoid TagLib's high level API for rendering just copying parts of + // the file that don't contain tag data. + // + // Now I'll explain the steps in this ugliness: + + // First, make sure that we're working with a buffer that is longer than + // the *differnce* in the tag sizes. We want to avoid overwriting parts + // that aren't yet in memory, so this is necessary. + + ulong bufferLength = bufferSize(); + while(data.size() - replace > bufferLength) + bufferLength += bufferSize(); + + // Set where to start the reading and writing. + + long readPosition = start + replace; + long writePosition = start; + + ByteVector buffer; + ByteVector aboutToOverwrite(static_cast(bufferLength)); + + // This is basically a special case of the loop below. Here we're just + // doing the same steps as below, but since we aren't using the same buffer + // size -- instead we're using the tag size -- this has to be handled as a + // special case. We're also using File::writeBlock() just for the tag. + // That's a bit slower than using char *'s so, we're only doing it here. + + seek(readPosition); + int bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file); + readPosition += bufferLength; + + seek(writePosition); + writeBlock(data); + writePosition += data.size(); + + buffer = aboutToOverwrite; + + // Ok, here's the main loop. We want to loop until the read fails, which + // means that we hit the end of the file. + + while(bytesRead != 0) { + + // Seek to the current read position and read the data that we're about + // to overwrite. Appropriately increment the readPosition. + + seek(readPosition); + bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file); + aboutToOverwrite.resize(bytesRead); + readPosition += bufferLength; + + // Check to see if we just read the last block. We need to call clear() + // if we did so that the last write succeeds. + + if(ulong(bytesRead) < bufferLength) + clear(); + + // Seek to the write position and write our buffer. Increment the + // writePosition. + + seek(writePosition); + fwrite(buffer.data(), sizeof(char), bufferLength, d->file); + writePosition += bufferLength; + + // Make the current buffer the data that we read in the beginning. + + buffer = aboutToOverwrite; + + // Again, we need this for the last write. We don't want to write garbage + // at the end of our file, so we need to set the buffer size to the amount + // that we actually read. + + bufferLength = bytesRead; + } +} + +void File::removeBlock(ulong start, ulong length) +{ + if(!d->file) + return; + + ulong bufferLength = bufferSize(); + + long readPosition = start + length; + long writePosition = start; + + ByteVector buffer(static_cast(bufferLength)); + + ulong bytesRead = true; + + while(bytesRead != 0) { + seek(readPosition); + bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file); + buffer.resize(bytesRead); + readPosition += bytesRead; + + // Check to see if we just read the last block. We need to call clear() + // if we did so that the last write succeeds. + + if(bytesRead < bufferLength) + clear(); + + seek(writePosition); + fwrite(buffer.data(), sizeof(char), bytesRead, d->file); + writePosition += bytesRead; + } + truncate(writePosition); +} + +bool File::readOnly() const +{ + return d->readOnly; +} + +bool File::isReadable(const char *file) +{ + return access(file, R_OK) == 0; +} + +bool File::isOpen() const +{ + return d->file; +} + +bool File::isValid() const +{ + return d->file && d->valid; +} + +void File::seek(long offset, Position p) +{ + if(!d->file) { + debug("File::seek() -- trying to seek in a file that isn't opened."); + return; + } + + switch(p) { + case Beginning: + fseek(d->file, offset, SEEK_SET); + break; + case Current: + fseek(d->file, offset, SEEK_CUR); + break; + case End: + fseek(d->file, offset, SEEK_END); + break; + } +} + +void File::clear() +{ + clearerr(d->file); +} + +long File::tell() const +{ + return ftell(d->file); +} + +long File::length() +{ + if(!d->file) + return 0; + + long curpos = tell(); + + seek(0, End); + long endpos = tell(); + + seek(curpos, Beginning); + + return endpos; +} + +bool File::isWritable(const char *file) +{ + return access(file, W_OK) == 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void File::setValid(bool valid) +{ + d->valid = valid; +} + +void File::truncate(long length) +{ + ftruncate(fileno(d->file), length); +} + +TagLib::uint File::bufferSize() +{ + return FilePrivate::bufferSize; +} diff --git a/Libraries/TagLib/Files/taglib/toolkit/tfile.h b/Libraries/TagLib/Files/taglib/toolkit/tfile.h new file mode 100644 index 000000000..bde30d200 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tfile.h @@ -0,0 +1,240 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_FILE_H +#define TAGLIB_FILE_H + +#include "taglib.h" +#include "tbytevector.h" + +namespace TagLib { + + class String; + class Tag; + class AudioProperties; + + //! A file class with some useful methods for tag manipulation + + /*! + * This class is a basic file class with some methods that are particularly + * useful for tag editors. It has methods to take advantage of + * ByteVector and a binary search method for finding patterns in a file. + */ + + class File + { + public: + /*! + * Position in the file used for seeking. + */ + enum Position { + //! Seek from the beginning of the file. + Beginning, + //! Seek from the current position in the file. + Current, + //! Seek from the end of the file. + End + }; + + /*! + * Destroys this File instance. + */ + virtual ~File(); + + /*! + * Returns the file name in the local file system encoding. + */ + const char *name() const; + + /*! + * Returns a pointer to this file's tag. This should be reimplemented in + * the concrete subclasses. + */ + virtual Tag *tag() const = 0; + + /*! + * Returns a pointer to this file's audio properties. This should be + * reimplemented in the concrete subclasses. If no audio properties were + * read then this will return a null pointer. + */ + virtual AudioProperties *audioProperties() const = 0; + + /*! + * Save the file and its associated tags. This should be reimplemented in + * the concrete subclasses. Returns true if the save succeeds. + */ + virtual bool save() = 0; + + /*! + * Reads a block of size \a length at the current get pointer. + */ + ByteVector readBlock(ulong length); + + /*! + * Attempts to write the block \a data at the current get pointer. If the + * file is currently only opened read only -- i.e. readOnly() returns true -- + * this attempts to reopen the file in read/write mode. + * + * \note This should be used instead of using the streaming output operator + * for a ByteVector. And even this function is significantly slower than + * doing output with a char[]. + */ + void writeBlock(const ByteVector &data); + + /*! + * Returns the offset in the file that \a pattern occurs at or -1 if it can + * not be found. If \a before is set, the search will only continue until the + * pattern \a before is found. This is useful for tagging purposes to search + * for a tag before the synch frame. + * + * Searching starts at \a fromOffset, which defaults to the beginning of the + * file. + * + * \note This has the practial limitation that \a pattern can not be longer + * than the buffer size used by readBlock(). Currently this is 1024 bytes. + */ + long find(const ByteVector &pattern, + long fromOffset = 0, + const ByteVector &before = ByteVector::null); + + /*! + * Returns the offset in the file that \a pattern occurs at or -1 if it can + * not be found. If \a before is set, the search will only continue until the + * pattern \a before is found. This is useful for tagging purposes to search + * for a tag before the synch frame. + * + * Searching starts at \a fromOffset and proceeds from the that point to the + * beginning of the file and defaults to the end of the file. + * + * \note This has the practial limitation that \a pattern can not be longer + * than the buffer size used by readBlock(). Currently this is 1024 bytes. + */ + long rfind(const ByteVector &pattern, + long fromOffset = 0, + const ByteVector &before = ByteVector::null); + + /*! + * Insert \a data at position \a start in the file overwriting \a replace + * bytes of the original content. + * + * \note This method is slow since it requires rewriting all of the file + * after the insertion point. + */ + void insert(const ByteVector &data, ulong start = 0, ulong replace = 0); + + /*! + * Removes a block of the file starting a \a start and continuing for + * \a length bytes. + * + * \note This method is slow since it involves rewriting all of the file + * after the removed portion. + */ + void removeBlock(ulong start = 0, ulong length = 0); + + /*! + * Returns true if the file is read only (or if the file can not be opened). + */ + bool readOnly() const; + + /*! + * Since the file can currently only be opened as an argument to the + * constructor (sort-of by design), this returns if that open succeeded. + */ + bool isOpen() const; + + /*! + * Returns true if the file is open and readble and valid information for + * the Tag and / or AudioProperties was found. + */ + bool isValid() const; + + /*! + * Move the I/O pointer to \a offset in the file from position \a p. This + * defaults to seeking from the beginning of the file. + * + * \see Position + */ + void seek(long offset, Position p = Beginning); + + /*! + * Reset the end-of-file and error flags on the file. + */ + void clear(); + + /*! + * Returns the current offset withing the file. + */ + long tell() const; + + /*! + * Returns the length of the file. + */ + long length(); + + /*! + * Returns true if \a file can be opened for reading. If the file does not + * exist, this will return false. + */ + static bool isReadable(const char *file); + + /*! + * Returns true if \a file can be opened for writing. + */ + static bool isWritable(const char *name); + + protected: + /*! + * Construct a File object and opens the \a file. \a file should be a + * be a C-string in the local file system encoding. + * + * \note Constructor is protected since this class should only be + * instantiated through subclasses. + */ + File(const char *file); + + /*! + * Marks the file as valid or invalid. + * + * \see isValid() + */ + void setValid(bool valid); + + /*! + * Truncates the file to a \a length. + */ + void truncate(long length); + + /*! + * Returns the buffer size that is used for internal buffering. + */ + static uint bufferSize(); + + private: + File(const File &); + File &operator=(const File &); + + class FilePrivate; + FilePrivate *d; + }; + +} + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tlist.h b/Libraries/TagLib/Files/taglib/toolkit/tlist.h new file mode 100644 index 000000000..3ea7a669e --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tlist.h @@ -0,0 +1,236 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_LIST_H +#define TAGLIB_LIST_H + +#include "taglib.h" + +#include + +namespace TagLib { + + //! A generic, implicitly shared list. + + /*! + * This is basic generic list that's somewhere between a std::list and a + * QValueList. This class is implicitly shared. For example: + * + * \code + * + * TagLib::List l = someOtherIntList; + * + * \endcode + * + * The above example is very cheap. This also makes lists suitable for the + * return types of functions. The above example will just copy a pointer rather + * than copying the data in the list. When your \e shared list's data changes, + * only \e then will the data be copied. + */ + + template class List + { + public: +#ifndef DO_NOT_DOCUMENT + typedef typename std::list::iterator Iterator; + typedef typename std::list::const_iterator ConstIterator; +#endif + + /*! + * Constructs an empty list. + */ + List(); + + /*! + * Make a shallow, implicitly shared, copy of \a l. Because this is + * implicitly shared, this method is lightweight and suitable for + * pass-by-value usage. + */ + List(const List &l); + + /*! + * Destroys this List instance. If auto deletion is enabled and this list + * contains a pointer type all of the memebers are also deleted. + */ + virtual ~List(); + + /*! + * Returns an STL style iterator to the beginning of the list. See + * std::list::const_iterator for the semantics. + */ + Iterator begin(); + + /*! + * Returns an STL style constant iterator to the beginning of the list. See + * std::list::iterator for the semantics. + */ + ConstIterator begin() const; + + /*! + * Returns an STL style iterator to the end of the list. See + * std::list::iterator for the semantics. + */ + Iterator end(); + + /*! + * Returns an STL style constant iterator to the end of the list. See + * std::list::const_iterator for the semantics. + */ + ConstIterator end() const; + + /*! + * Inserts a copy of \a value before \a it. + */ + void insert(Iterator it, const T &value); + + /*! + * Inserts the \a value into the list. This assumes that the list is + * currently sorted. If \a unique is true then the value will not + * be inserted if it is already in the list. + */ + void sortedInsert(const T &value, bool unique = false); + + /*! + * Appends \a item to the end of the list and returns a reference to the + * list. + */ + List &append(const T &item); + + /*! + * Appends all of the values in \a l to the end of the list and returns a + * reference to the list. + */ + List &append(const List &l); + + /*! + * Clears the list. If auto deletion is enabled and this list contains a + * pointer type the members are also deleted. + * + * \see setAutoDelete() + */ + void clear(); + + /*! + * Returns the number of elements in the list. + */ + uint size() const; + bool isEmpty() const; + + /*! + * Find the first occurance of \a value. + */ + Iterator find(const T &value); + + /*! + * Find the first occurance of \a value. + */ + ConstIterator find(const T &value) const; + + /*! + * Returns true if the list contains \a value. + */ + bool contains(const T &value) const; + + /*! + * Erase the item at \a it from the list. + */ + void erase(Iterator it); + + /*! + * Returns a reference to the first item in the list. + */ + const T &front() const; + + /*! + * Returns a reference to the first item in the list. + */ + T &front(); + + /*! + * Returns a reference to the last item in the list. + */ + const T &back() const; + + /*! + * Returns a reference to the last item in the list. + */ + T &back(); + + /*! + * Auto delete the members of the list when the last reference to the list + * passes out of scope. This will have no effect on lists which do not + * contain a pointer type. + * + * \note This relies on partial template instantiation -- most modern C++ + * compilers should now support this. + */ + void setAutoDelete(bool autoDelete); + + /*! + * Returns a reference to item \a i in the list. + * + * \warning This method is slow. Use iterators to loop through the list. + */ + T &operator[](uint i); + + /*! + * Returns a const reference to item \a i in the list. + * + * \warning This method is slow. Use iterators to loop through the list. + */ + const T &operator[](uint i) const; + + /*! + * Make a shallow, implicitly shared, copy of \a l. Because this is + * implicitly shared, this method is lightweight and suitable for + * pass-by-value usage. + */ + List &operator=(const List &l); + + /*! + * Compares this list with \a l and returns true if all of the elements are + * the same. + */ + bool operator==(const List &l) const; + + protected: + /* + * If this List is being shared via implicit sharing, do a deep copy of the + * data and separate from the shared members. This should be called by all + * non-const subclass members. + */ + void detach(); + + private: +#ifndef DO_NOT_DOCUMENT + template class ListPrivate; + ListPrivate *d; +#endif + }; + +} + +// Since GCC doesn't support the "export" keyword, we have to include the +// implementation. + +#include "tlist.tcc" + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tlist.tcc b/Libraries/TagLib/Files/taglib/toolkit/tlist.tcc new file mode 100644 index 000000000..e94b85a71 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tlist.tcc @@ -0,0 +1,296 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include + +#include + +namespace TagLib { + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +// The functionality of List::setAutoDelete() is implemented here partial +// template specialization. This is implemented in such a way that calling +// setAutoDelete() on non-pointer types will simply have no effect. + +// A base for the generic and specialized private class types. New +// non-templatized members should be added here. + +class ListPrivateBase : public RefCounter +{ +public: + ListPrivateBase() : autoDelete(false) {} + bool autoDelete; +}; + +// A generic implementation + +template +template class List::ListPrivate : public ListPrivateBase +{ +public: + ListPrivate() : ListPrivateBase() {} + ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} + void clear() { + list.clear(); + } + std::list list; +}; + +// A partial specialization for all pointer types that implements the +// setAutoDelete() functionality. + +template +template class List::ListPrivate : public ListPrivateBase +{ +public: + ListPrivate() : ListPrivateBase() {} + ListPrivate(const std::list &l) : ListPrivateBase(), list(l) {} + ~ListPrivate() { + clear(); + } + void clear() { + if(autoDelete) { + typename std::list::const_iterator it = list.begin(); + for(; it != list.end(); ++it) + delete *it; + } + list.clear(); + } + std::list list; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +template +List::List() +{ + d = new ListPrivate; +} + +template +List::List(const List &l) : d(l.d) +{ + d->ref(); +} + +template +List::~List() +{ + if(d->deref()) + delete d; +} + +template +typename List::Iterator List::begin() +{ + detach(); + return d->list.begin(); +} + +template +typename List::ConstIterator List::begin() const +{ + return d->list.begin(); +} + +template +typename List::Iterator List::end() +{ + detach(); + return d->list.end(); +} + +template +typename List::ConstIterator List::end() const +{ + return d->list.end(); +} + +template +void List::insert(Iterator it, const T &item) +{ + detach(); + d->list.insert(it, item); +} + +template +void List::sortedInsert(const T &value, bool unique) +{ + detach(); + Iterator it = begin(); + while(*it < value && it != end()) + ++it; + if(unique && it != end() && *it == value) + return; + insert(it, value); +} + +template +List &List::append(const T &item) +{ + detach(); + d->list.push_back(item); + return *this; +} + +template +List &List::append(const List &l) +{ + detach(); + d->list.insert(d->list.end(), l.begin(), l.end()); + return *this; +} + +template +void List::clear() +{ + detach(); + d->clear(); +} + +template +TagLib::uint List::size() const +{ + return d->list.size(); +} + +template +bool List::isEmpty() const +{ + return d->list.empty(); +} + +template +typename List::Iterator List::find(const T &value) +{ + return std::find(d->list.begin(), d->list.end(), value); +} + +template +typename List::ConstIterator List::find(const T &value) const +{ + return std::find(d->list.begin(), d->list.end(), value); +} + +template +bool List::contains(const T &value) const +{ + return std::find(d->list.begin(), d->list.end(), value) != d->list.end(); +} + +template +void List::erase(Iterator it) +{ + d->list.erase(it); +} + +template +const T &List::front() const +{ + return d->list.front(); +} + +template +T &List::front() +{ + detach(); + return d->list.front(); +} + +template +const T &List::back() const +{ + return d->list.back(); +} + +template +void List::setAutoDelete(bool autoDelete) +{ + d->autoDelete = autoDelete; +} + +template +T &List::back() +{ + detach(); + return d->list.back(); +} + +template +T &List::operator[](uint i) +{ + Iterator it = d->list.begin(); + + for(uint j = 0; j < i; j++) + ++it; + + return *it; +} + +template +const T &List::operator[](uint i) const +{ + ConstIterator it = d->list.begin(); + + for(uint j = 0; j < i; j++) + ++it; + + return *it; +} + +template +List &List::operator=(const List &l) +{ + if(&l == this) + return *this; + + if(d->deref()) + delete d; + d = l.d; + d->ref(); + return *this; +} + +template +bool List::operator==(const List &l) const +{ + return d->list == l.d->list; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +template +void List::detach() +{ + if(d->count() > 1) { + d->deref(); + d = new ListPrivate(d->list); + } +} + +} // namespace TagLib diff --git a/Libraries/TagLib/Files/taglib/toolkit/tmap.h b/Libraries/TagLib/Files/taglib/toolkit/tmap.h new file mode 100644 index 000000000..f67bcbaad --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tmap.h @@ -0,0 +1,177 @@ +/*************************************************************************** + copyright : (C) 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_MAP_H +#define TAGLIB_MAP_H + +#include "taglib.h" + +#include + +namespace TagLib { + + //! A generic, implicitly shared map. + + /*! + * This implements a standard map container that associates a key with a value + * and has fast key-based lookups. This map is also implicitly shared making + * it suitable for pass-by-value usage. + */ + + template class Map + { + public: +#ifndef DO_NOT_DOCUMENT + typedef typename std::map::iterator Iterator; + typedef typename std::map::const_iterator ConstIterator; +#endif + + /*! + * Constructs an empty Map. + */ + Map(); + + /*! + * Make a shallow, implicitly shared, copy of \a m. Because this is + * implicitly shared, this method is lightweight and suitable for + * pass-by-value usage. + */ + Map(const Map &m); + + /*! + * Destroys this instance of the Map. + */ + virtual ~Map(); + + /*! + * Returns an STL style iterator to the beginning of the map. See + * std::map::iterator for the semantics. + */ + Iterator begin(); + + /*! + * Returns an STL style iterator to the beginning of the map. See + * std::map::const_iterator for the semantics. + */ + ConstIterator begin() const; + + /*! + * Returns an STL style iterator to the end of the map. See + * std::map::iterator for the semantics. + */ + Iterator end(); + + /*! + * Returns an STL style iterator to the end of the map. See + * std::map::const_iterator for the semantics. + */ + ConstIterator end() const; + + /*! + * Inserts \a value under \a key in the map. If a value for \a key already + * exists it will be overwritten. + */ + void insert(const Key &key, const T &value); + + /*! + * Removes all of the elements from elements from the map. This however + * will not delete pointers if the mapped type is a pointer type. + */ + void clear(); + + /*! + * The number of elements in the map. + * + * \see isEmpty() + */ + uint size() const; + + /*! + * Returns true if the map is empty. + * + * \see size() + */ + bool isEmpty() const; + + /*! + * Find the first occurance of \a key. + */ + Iterator find(const Key &key); + + /*! + * Find the first occurance of \a key. + */ + ConstIterator find(const Key &key) const; + + /*! + * Returns true if the map contains an instance of \a key. + */ + bool contains(const Key &key) const; + + /*! + * Erase the item at \a it from the list. + */ + void erase(Iterator it); + + /*! + * Returns a reference to the value associated with \a key. + * + * \note This has undefined behavior if the key is not present in the map. + */ + const T &operator[](const Key &key) const; + + /*! + * Returns a reference to the value associated with \a key. + * + * \note This has undefined behavior if the key is not present in the map. + */ + T &operator[](const Key &key); + + /*! + * Make a shallow, implicitly shared, copy of \a m. Because this is + * implicitly shared, this method is lightweight and suitable for + * pass-by-value usage. + */ + Map &operator=(const Map &m); + + protected: + /* + * If this List is being shared via implicit sharing, do a deep copy of the + * data and separate from the shared members. This should be called by all + * non-const subclass members. + */ + void detach(); + + private: +#ifndef DO_NOT_DOCUMENT + template class MapPrivate; + MapPrivate *d; +#endif + }; + +} + +// Since GCC doesn't support the "export" keyword, we have to include the +// implementation. + +#include "tmap.tcc" + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tmap.tcc b/Libraries/TagLib/Files/taglib/toolkit/tmap.tcc new file mode 100644 index 000000000..fff5f6649 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tmap.tcc @@ -0,0 +1,172 @@ +/*************************************************************************** + copyright : (C) 2002 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +namespace TagLib { + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +template +template class Map::MapPrivate : public RefCounter +{ +public: + MapPrivate() : RefCounter() {} + MapPrivate(const std::map &m) : RefCounter(), map(m) {} + + std::map map; +}; + +template +Map::Map() +{ + d = new MapPrivate; +} + +template +Map::Map(const Map &m) : d(m.d) +{ + d->ref(); +} + +template +Map::~Map() +{ + if(d->deref()) + delete(d); +} + +template +typename Map::Iterator Map::begin() +{ + detach(); + return d->map.begin(); +} + +template +typename Map::ConstIterator Map::begin() const +{ + return d->map.begin(); +} + +template +typename Map::Iterator Map::end() +{ + detach(); + return d->map.end(); +} + +template +typename Map::ConstIterator Map::end() const +{ + return d->map.end(); +} + +template +void Map::insert(const Key &key, const T &value) +{ + detach(); + std::pair item(key, value); + d->map.insert(item); +} + +template +void Map::clear() +{ + detach(); + d->map.clear(); +} + +template +bool Map::isEmpty() const +{ + return d->map.empty(); +} + +template +typename Map::Iterator Map::find(const Key &key) +{ + return d->map.find(key); +} + +template +typename Map::ConstIterator Map::find(const Key &key) const +{ + return d->map.find(key); +} + +template +bool Map::contains(const Key &key) const +{ + return d->map.find(key) != d->map.end(); +} + +template +void Map::erase(Iterator it) +{ + d->map.erase(it); +} + +template +TagLib::uint Map::size() const +{ + return d->map.size(); +} + +template +const T &Map::operator[](const Key &key) const +{ + return d->map[key]; +} + +template +T &Map::operator[](const Key &key) +{ + return d->map[key]; +} + +template +Map &Map::operator=(const Map &m) +{ + if(&m == this) + return *this; + + if(d->deref()) + delete(d); + d = m.d; + d->ref(); + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +template +void Map::detach() +{ + if(d->count() > 1) { + d->deref(); + d = new MapPrivate(d->map); + } +} + +} // namespace TagLib diff --git a/Libraries/TagLib/Files/taglib/toolkit/tstring.cpp b/Libraries/TagLib/Files/taglib/toolkit/tstring.cpp new file mode 100644 index 000000000..c6b89218e --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tstring.cpp @@ -0,0 +1,723 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "tstring.h" +#include "unicode.h" +#include "tdebug.h" + +#include + +namespace TagLib { + + inline unsigned short byteSwap(unsigned short x) + { + return ((x) >> 8) & 0xff | ((x) & 0xff) << 8; + } + + inline unsigned short combine(unsigned char c1, unsigned char c2) + { + return (c1 << 8) | c2; + } +} + +using namespace TagLib; + +class String::StringPrivate : public RefCounter +{ +public: + StringPrivate(const wstring &s) : + RefCounter(), + data(s), + CString(0) {} + + StringPrivate() : + RefCounter(), + CString(0) {} + + ~StringPrivate() { + delete [] CString; + } + + wstring data; + + /*! + * This is only used to hold the a pointer to the most recent value of + * toCString. + */ + char *CString; +}; + +String String::null; + +//////////////////////////////////////////////////////////////////////////////// + +String::String() +{ + d = new StringPrivate; +} + +String::String(const String &s) : d(s.d) +{ + d->ref(); +} + +String::String(const std::string &s, Type t) +{ + d = new StringPrivate; + + if(t == UTF16 || t == UTF16BE) { + debug("String::String() -- A std::string should not contain UTF16."); + return; + } + + int length = s.length(); + d->data.resize(length); + wstring::iterator targetIt = d->data.begin(); + + for(std::string::const_iterator it = s.begin(); it != s.end(); it++) { + *targetIt = uchar(*it); + ++targetIt; + } + + prepare(t); +} + +String::String(const wstring &s, Type t) +{ + d = new StringPrivate(s); + prepare(t); +} + +String::String(const wchar_t *s, Type t) +{ + d = new StringPrivate(s); + prepare(t); +} + +String::String(const char *s, Type t) +{ + d = new StringPrivate; + + if(t == UTF16 || t == UTF16BE) { + debug("String::String() -- A const char * should not contain UTF16."); + return; + } + + int length = ::strlen(s); + d->data.resize(length); + + wstring::iterator targetIt = d->data.begin(); + + for(int i = 0; i < length; i++) { + *targetIt = uchar(s[i]); + ++targetIt; + } + + prepare(t); +} + +String::String(wchar_t c, Type t) +{ + d = new StringPrivate; + d->data += c; + prepare(t); +} + +String::String(char c, Type t) +{ + d = new StringPrivate; + + if(t == UTF16 || t == UTF16BE) { + debug("String::String() -- A std::string should not contain UTF16."); + return; + } + + d->data += uchar(c); + prepare(t); +} + +String::String(const ByteVector &v, Type t) +{ + d = new StringPrivate; + + if(v.isEmpty()) + return; + + if(t == Latin1 || t == UTF8) { + + int length = 0; + d->data.resize(v.size()); + wstring::iterator targetIt = d->data.begin(); + for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) { + *targetIt = uchar(*it); + ++targetIt; + ++length; + } + d->data.resize(length); + } + else { + d->data.resize(v.size() / 2); + wstring::iterator targetIt = d->data.begin(); + + for(ByteVector::ConstIterator it = v.begin(); + it != v.end() && it + 1 != v.end() && combine(*it, *(it + 1)); + it += 2) + { + *targetIt = combine(*it, *(it + 1)); + ++targetIt; + } + } + prepare(t); +} + +//////////////////////////////////////////////////////////////////////////////// + +String::~String() +{ + if(d->deref()) + delete d; +} + +std::string String::to8Bit(bool unicode) const +{ + std::string s; + s.resize(d->data.size()); + + if(!unicode) { + std::string::iterator targetIt = s.begin(); + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + *targetIt = char(*it); + ++targetIt; + } + return s; + } + + const int outputBufferSize = d->data.size() * 3 + 1; + + Unicode::UTF16 *sourceBuffer = new Unicode::UTF16[d->data.size() + 1]; + Unicode::UTF8 *targetBuffer = new Unicode::UTF8[outputBufferSize]; + + for(unsigned int i = 0; i < d->data.size(); i++) + sourceBuffer[i] = Unicode::UTF16(d->data[i]); + + const Unicode::UTF16 *source = sourceBuffer; + Unicode::UTF8 *target = targetBuffer; + + Unicode::ConversionResult result = + Unicode::ConvertUTF16toUTF8(&source, sourceBuffer + d->data.size(), + &target, targetBuffer + outputBufferSize, + Unicode::lenientConversion); + + if(result != Unicode::conversionOK) + debug("String::to8Bit() - Unicode conversion error."); + + int newSize = target - targetBuffer; + s.resize(newSize); + targetBuffer[newSize] = 0; + + s = (char *) targetBuffer; + + delete [] sourceBuffer; + delete [] targetBuffer; + + return s; +} + +const char *String::toCString(bool unicode) const +{ + delete [] d->CString; + + std::string buffer = to8Bit(unicode); + d->CString = new char[buffer.size() + 1]; + strcpy(d->CString, buffer.c_str()); + + return d->CString; +} + +String::Iterator String::begin() +{ + return d->data.begin(); +} + +String::ConstIterator String::begin() const +{ + return d->data.begin(); +} + +String::Iterator String::end() +{ + return d->data.end(); +} + +String::ConstIterator String::end() const +{ + return d->data.end(); +} + +int String::find(const String &s, int offset) const +{ + wstring::size_type position = d->data.find(s.d->data, offset); + + if(position != wstring::npos) + return position; + else + return -1; +} + +String String::substr(uint position, uint n) const +{ + if(n > position + d->data.size()) + n = d->data.size() - position; + + String s; + s.d->data = d->data.substr(position, n); + return s; +} + +String &String::append(const String &s) +{ + detach(); + d->data += s.d->data; + return *this; +} + +String String::upper() const +{ + String s; + + static int shift = 'A' - 'a'; + + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); ++it) { + if(*it >= 'a' && *it <= 'z') + s.d->data.push_back(*it + shift); + else + s.d->data.push_back(*it); + } + + return s; +} + +TagLib::uint String::size() const +{ + return d->data.size(); +} + +bool String::isEmpty() const +{ + return d->data.size() == 0; +} + +bool String::isNull() const +{ + return d == null.d; +} + +ByteVector String::data(Type t) const +{ + ByteVector v; + + switch(t) { + + case Latin1: + { + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) + v.append(char(*it)); + break; + } + case UTF8: + { + std::string s = to8Bit(true); + v.setData(s.c_str(), s.length()); + break; + } + case UTF16: + { + // Assume that if we're doing UTF16 and not UTF16BE that we want little + // endian encoding. (Byte Order Mark) + + v.append(char(0xff)); + v.append(char(0xfe)); + + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + + char c1 = *it & 0xff; + char c2 = *it >> 8; + + v.append(c1); + v.append(c2); + } + break; + } + case UTF16BE: + { + for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { + + char c1 = *it >> 8; + char c2 = *it & 0xff; + + v.append(c2); + v.append(c1); + } + break; + } + } + + return v; +} + +int String::toInt() const +{ + int value = 0; + + bool negative = d->data[0] == '-'; + uint i = negative ? 1 : 0; + + for(; i < d->data.size() && d->data[i] >= '0' && d->data[i] <= '9'; i++) + value = value * 10 + (d->data[i] - '0'); + + if(negative) + value = value * -1; + + return value; +} + +String String::stripWhiteSpace() const +{ + wstring::const_iterator begin = d->data.begin(); + wstring::const_iterator end = d->data.end(); + + while(*begin == '\t' || *begin == '\n' || *begin == '\f' || + *begin == '\r' || *begin == ' ' && begin != end) + { + ++begin; + } + + if(begin == end) + return null; + + // There must be at least one non-whitespace charater here for us to have + // gotten this far, so we should be safe not doing bounds checking. + + do { + --end; + } while(*end == '\t' || *end == '\n' || + *end == '\f' || *end == '\r' || *end == ' '); + + return String(wstring(begin, end + 1)); +} + +String String::number(int n) // static +{ + if(n == 0) + return String("0"); + + String charStack; + + bool negative = n < 0; + + if(negative) + n = n * -1; + + while(n > 0) { + int remainder = n % 10; + charStack += char(remainder + '0'); + n = (n - remainder) / 10; + } + + String s; + + if(negative) + s += '-'; + + for(int i = charStack.d->data.size() - 1; i >= 0; i--) + s += charStack.d->data[i]; + + return s; +} + +TagLib::wchar &String::operator[](int i) +{ + return d->data[i]; +} + +const TagLib::wchar &String::operator[](int i) const +{ + return d->data[i]; +} + +bool String::operator==(const String &s) const +{ + return d == s.d || d->data == s.d->data; +} + +String &String::operator+=(const String &s) +{ + detach(); + + d->data += s.d->data; + return *this; +} + +String &String::operator+=(const wchar_t *s) +{ + detach(); + + d->data += s; + return *this; +} + +String &String::operator+=(const char *s) +{ + detach(); + + for(int i = 0; s[i] != 0; i++) + d->data += uchar(s[i]); + return *this; +} + +String &String::operator+=(wchar_t c) +{ + detach(); + + d->data += c; + return *this; +} + +String &String::operator+=(char c) +{ + d->data += uchar(c); + return *this; +} + +String &String::operator=(const String &s) +{ + if(&s == this) + return *this; + + if(d->deref()) + delete d; + d = s.d; + d->ref(); + return *this; +} + +String &String::operator=(const std::string &s) +{ + if(d->deref()) + delete d; + + d = new StringPrivate; + + d->data.resize(s.size()); + + wstring::iterator targetIt = d->data.begin(); + for(std::string::const_iterator it = s.begin(); it != s.end(); it++) { + *targetIt = uchar(*it); + ++targetIt; + } + + return *this; +} + +String &String::operator=(const wstring &s) +{ + if(d->deref()) + delete d; + d = new StringPrivate(s); + return *this; +} + +String &String::operator=(const wchar_t *s) +{ + if(d->deref()) + delete d; + d = new StringPrivate(s); + return *this; +} + +String &String::operator=(char c) +{ + if(d->deref()) + delete d; + d = new StringPrivate; + d->data += uchar(c); + return *this; +} + +String &String::operator=(wchar_t c) +{ + if(d->deref()) + delete d; + d = new StringPrivate; + d->data += c; + return *this; +} + +String &String::operator=(const char *s) +{ + if(d->deref()) + delete d; + + d = new StringPrivate; + + int length = ::strlen(s); + d->data.resize(length); + + wstring::iterator targetIt = d->data.begin(); + for(int i = 0; i < length; i++) { + *targetIt = uchar(s[i]); + ++targetIt; + } + + return *this; +} + +String &String::operator=(const ByteVector &v) +{ + if(d->deref()) + delete d; + + d = new StringPrivate; + d->data.resize(v.size()); + wstring::iterator targetIt = d->data.begin(); + + uint i = 0; + + for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) { + *targetIt = uchar(*it); + ++targetIt; + ++i; + } + + // If we hit a null in the ByteVector, shrink the string again. + + d->data.resize(i); + + return *this; +} + +bool String::operator<(const String &s) const +{ + return d->data < s.d->data; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +void String::detach() +{ + if(d->count() > 1) { + d->deref(); + d = new StringPrivate(d->data); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void String::prepare(Type t) +{ + switch(t) { + case UTF16: + { + if(d->data.size() > 1) { + bool swap = d->data[0] != 0xfeff; + d->data.erase(d->data.begin(), d->data.begin() + 1); + if(swap) { + for(uint i = 0; i < d->data.size(); i++) + d->data[i] = byteSwap((unsigned short)d->data[i]); + } + } + else { + debug("String::prepare() - Invalid UTF16 string."); + d->data.erase(d->data.begin(), d->data.end()); + } + break; + } + case UTF8: + { + int bufferSize = d->data.size() + 1; + Unicode::UTF8 *sourceBuffer = new Unicode::UTF8[bufferSize]; + Unicode::UTF16 *targetBuffer = new Unicode::UTF16[bufferSize]; + + unsigned int i = 0; + for(; i < d->data.size(); i++) + sourceBuffer[i] = Unicode::UTF8(d->data[i]); + sourceBuffer[i] = 0; + + const Unicode::UTF8 *source = sourceBuffer; + Unicode::UTF16 *target = targetBuffer; + + Unicode::ConversionResult result = + Unicode::ConvertUTF8toUTF16(&source, sourceBuffer + bufferSize, + &target, targetBuffer + bufferSize, + Unicode::lenientConversion); + + if(result != Unicode::conversionOK) + debug("String::prepare() - Unicode conversion error."); + + + int newSize = target != targetBuffer ? target - targetBuffer - 1 : 0; + d->data.resize(newSize); + + for(int i = 0; i < newSize; i++) + d->data[i] = targetBuffer[i]; + + delete [] sourceBuffer; + delete [] targetBuffer; + } + default: + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// related functions +//////////////////////////////////////////////////////////////////////////////// + +const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2) +{ + String s(s1); + s.append(s2); + return s; +} + +const TagLib::String operator+(const char *s1, const TagLib::String &s2) +{ + String s(s1); + s.append(s2); + return s; +} + +const TagLib::String operator+(const TagLib::String &s1, const char *s2) +{ + String s(s1); + s.append(s2); + return s; +} + +std::ostream &operator<<(std::ostream &s, const String &str) +{ + s << str.to8Bit(); + return s; +} diff --git a/Libraries/TagLib/Files/taglib/toolkit/tstring.h b/Libraries/TagLib/Files/taglib/toolkit/tstring.h new file mode 100644 index 000000000..6ffd65630 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tstring.h @@ -0,0 +1,414 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_STRING_H +#define TAGLIB_STRING_H + +#include "taglib.h" +#include "tbytevector.h" + +#include + +/*! + * \relates TagLib::String + * + * Converts a TagLib::String to a QString without a requirement to link to Qt. + */ +#define QStringToTString(s) TagLib::String(s.utf8().data(), TagLib::String::UTF8) + +/*! + * \relates TagLib::String + * + * Converts a TagLib::String to a QString without a requirement to link to Qt. + */ +#define TStringToQString(s) QString::fromUtf8(s.toCString(true)) + +namespace TagLib { + + //! A \e wide string class suitable for unicode. + + /*! + * This is an implicitly shared \e wide string. For storage it uses + * TagLib::wstring, but as this is an implementation detail this of + * course could change. Strings are stored internally as UTF-16BE. (Without + * the BOM (Byte Order Mark) + * + * The use of implicit sharing means that copying a string is cheap, the only + * \e cost comes into play when the copy is modified. Prior to that the string + * just has a pointer to the data of the \e parent String. This also makes + * this class suitable as a function return type. + * + * In addition to adding implicit sharing, this class keeps track of four + * possible encodings, which are the four supported by the ID3v2 standard. + */ + + class String + { + public: + +#ifndef DO_NOT_DOCUMENT + typedef std::basic_string::iterator Iterator; + typedef std::basic_string::const_iterator ConstIterator; +#endif + + /** + * The four types of string encodings supported by the ID3v2 specification. + * ID3v1 is assumed to be Latin1 and Ogg Vorbis comments use UTF8. + */ + enum Type { + /*! + * IS08859-1, or Latin1 encoding. 8 bit characters. + */ + Latin1 = 0, + /*! + * UTF16 with a byte order mark. 16 bit characters. + */ + UTF16 = 1, + /*! + * UTF16 big endian. 16 bit characters. This is the encoding used + * internally by TagLib. + */ + UTF16BE = 2, + /*! + * UTF8 encoding. Characters are usually 8 bits but can be up to 32. + */ + UTF8 = 3 + }; + + /*! + * Constructs an empty String. + */ + String(); + + /*! + * Make a shallow, implicitly shared, copy of \a s. Because this is + * implicitly shared, this method is lightweight and suitable for + * pass-by-value usage. + */ + String(const String &s); + + /*! + * Makes a deep copy of the data in \a s. + * + * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when + * used with other codecs it will simply print a warning and exit. + */ + String(const std::string &s, Type t = Latin1); + + /*! + * Makes a deep copy of the data in \a s. + */ + String(const wstring &s, Type t = UTF16BE); + + /*! + * Makes a deep copy of the data in \a s. + */ + String(const wchar_t *s, Type t = UTF16BE); + + /*! + * Makes a deep copy of the data in \a c. + * + * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when + * used with other codecs it will simply print a warning and exit. + */ + String(char c, Type t = Latin1); + + /*! + * Makes a deep copy of the data in \a c. + */ + String(wchar_t c, Type t = Latin1); + + + /*! + * Makes a deep copy of the data in \a s. + * + * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when + * used with other codecs it will simply print a warning and exit. + */ + String(const char *s, Type t = Latin1); + + /*! + * Makes a deep copy of the data in \a s. + * + * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when + * used with other codecs it will simply print a warning and exit. + */ + String(const ByteVector &v, Type t = Latin1); + + /*! + * Destroys this String instance. + */ + virtual ~String(); + + /*! + * If \a unicode if false (the default) this will return a \e Latin1 encoded + * std::string. If it is true the returned std::wstring will be UTF-8 + * encoded. + */ + std::string to8Bit(bool unicode = false) const; + + /*! + * Creates and returns a C-String based on the data. This string is still + * owned by the String (class) and as such should not be deleted by the user. + * + * If \a unicode if false (the default) this string will be encoded in + * \e Latin1. If it is true the returned C-String will be UTF-8 encoded. + * + * This string remains valid until the String instance is destroyed or + * another export method is called. + * + * \warning This however has the side effect that this C-String will remain + * in memory in addition to other memory that is consumed by the + * String instance. So, this method should not be used on large strings or + * where memory is critical. + */ + const char *toCString(bool unicode = false) const; + + /*! + * Returns an iterator pointing to the beginning of the string. + */ + Iterator begin(); + + /*! + * Returns a const iterator pointing to the beginning of the string. + */ + ConstIterator begin() const; + + /*! + * Returns an iterator pointing to the end of the string (the position + * after the last character). + */ + Iterator end(); + + /*! + * Returns a const iterator pointing to the end of the string (the position + * after the last character). + */ + ConstIterator end() const; + + /*! + * Finds the first occurance of pattern \a s in this string starting from + * \a offset. If the pattern is not found, -1 is returned. + */ + int find(const String &s, int offset = 0) const; + + /*! + * Extract a substring from this string starting at \a position and + * continuing for \a n characters. + */ + String substr(uint position, uint n = 0xffffffff) const; + + /*! + * Append \a s to the current string and return a reference to the current + * string. + */ + String &append(const String &s); + + /*! + * Returns an upper case version of the string. + * + * \warning This only works for the characters in US-ASCII, i.e. A-Z. + */ + String upper() const; + + /*! + * Returns the size of the string. + */ + uint size() const; + + /*! + * Returns true if the string is empty. + * + * \see isNull() + */ + bool isEmpty() const; + + /*! + * Returns true if this string is null -- i.e. it is a copy of the + * String::null string. + * + * \note A string can be empty and not null. + * \see isEmpty() + */ + bool isNull() const; + + /*! + * Returns a ByteVector containing the string's data. If \a t is Latin1 or + * UTF8, this will return a vector of 8 bit characters, otherwise it will use + * 16 bit characters. + */ + ByteVector data(Type t) const; + + /*! + * Convert the string to an integer. + */ + int toInt() const; + + /*! + * Returns a string with the leading and trailing whitespace stripped. + */ + String stripWhiteSpace() const; + + /*! + * Converts the base-10 integer \a n to a string. + */ + static String number(int n); + + /*! + * Returns a reference to the character at position \a i. + */ + wchar &operator[](int i); + + /*! + * Returns a const reference to the character at position \a i. + */ + const wchar &operator[](int i) const; + + /*! + * Compares each character of the String with each character of \a s and + * returns true if the strings match. + */ + bool operator==(const String &s) const; + + /*! + * Appends \a s to the end of the String. + */ + String &operator+=(const String &s); + + /*! + * Appends \a s to the end of the String. + */ + String &operator+=(const wchar_t* s); + + /*! + * Appends \a s to the end of the String. + */ + String &operator+=(const char* s); + + /*! + * Appends \a s to the end of the String. + */ + String &operator+=(wchar_t c); + + /*! + * Appends \a c to the end of the String. + */ + String &operator+=(char c); + + /*! + * Performs a shallow, implicitly shared, copy of \a s, overwriting the + * String's current data. + */ + String &operator=(const String &s); + + /*! + * Performs a deep copy of the data in \a s. + */ + String &operator=(const std::string &s); + + /*! + * Performs a deep copy of the data in \a s. + */ + String &operator=(const wstring &s); + + /*! + * Performs a deep copy of the data in \a s. + */ + String &operator=(const wchar_t *s); + + /*! + * Performs a deep copy of the data in \a s. + */ + String &operator=(char c); + + /*! + * Performs a deep copy of the data in \a s. + */ + String &operator=(wchar_t c); + + /*! + * Performs a deep copy of the data in \a s. + */ + String &operator=(const char *s); + + /*! + * Performs a deep copy of the data in \a v. + */ + String &operator=(const ByteVector &v); + + /*! + * To be able to use this class in a Map, this operator needed to be + * implemented. Returns true if \a s is less than this string in a bytewise + * comparison. + */ + bool operator<(const String &s) const; + + /*! + * A null string provided for convenience. + */ + static String null; + + protected: + /*! + * If this String is being shared via implicit sharing, do a deep copy of the + * data and separate from the shared members. This should be called by all + * non-const subclass members. + */ + void detach(); + + private: + /*! + * This checks to see if the string is in \e UTF-16 (with BOM) or \e UTF-8 + * format and if so converts it to \e UTF-16BE for internal use. \e Latin1 + * does not require conversion since it is a subset of \e UTF-16BE and + * \e UTF16-BE requires no conversion since it is used internally. + */ + void prepare(Type t); + + class StringPrivate; + StringPrivate *d; + }; + +} + +/*! + * \relates TagLib::String + */ +const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2); + +/*! + * \relates TagLib::String + */ +const TagLib::String operator+(const char *s1, const TagLib::String &s2); + +/*! + * \relates TagLib::String + */ +const TagLib::String operator+(const TagLib::String &s1, const char *s2); + + +/*! + * \relates TagLib::String + * Send the string to an output stream. + */ +std::ostream &operator<<(std::ostream &s, const TagLib::String &str); + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/tstringlist.cpp b/Libraries/TagLib/Files/taglib/toolkit/tstringlist.cpp new file mode 100644 index 000000000..f37b30bf8 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tstringlist.cpp @@ -0,0 +1,118 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include "tstringlist.h" + +using namespace TagLib; + +class StringListPrivate +{ + +}; + +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +StringList StringList::split(const String &s, const String &pattern) +{ + StringList l; + + int previousOffset = 0; + for(int offset = s.find(pattern); offset != -1; offset = s.find(pattern, offset + 1)) { + l.append(s.substr(previousOffset, offset - previousOffset)); + previousOffset = offset + 1; + } + + l.append(s.substr(previousOffset, s.size() - previousOffset)); + + return l; +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +StringList::StringList() : List() +{ + +} + +StringList::StringList(const StringList &l) : List(l) +{ + +} + +StringList::StringList(const String &s) : List() +{ + append(s); +} + +StringList::StringList(const ByteVectorList &bl, String::Type t) : List() +{ + ByteVectorList::ConstIterator i = bl.begin(); + for(;i != bl.end(); i++) { + append(String(*i, t)); + } +} + +StringList::~StringList() +{ + +} + +String StringList::toString(const String &separator) const +{ + String s; + + ConstIterator it = begin(); + + while(it != end()) { + s += *it; + it++; + if(it != end()) + s += separator; + } + + return s; +} + +StringList &StringList::append(const String &s) +{ + List::append(s); + return *this; +} + +StringList &StringList::append(const StringList &l) +{ + List::append(l); + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +// related functions +//////////////////////////////////////////////////////////////////////////////// + +std::ostream &operator<<(std::ostream &s, const StringList &l) +{ + s << l.toString(); + return s; +} diff --git a/Libraries/TagLib/Files/taglib/toolkit/tstringlist.h b/Libraries/TagLib/Files/taglib/toolkit/tstringlist.h new file mode 100644 index 000000000..5a2219e21 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/tstringlist.h @@ -0,0 +1,110 @@ +/*************************************************************************** + copyright : (C) 2002, 2003 by Scott Wheeler + email : wheeler@kde.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_STRINGLIST_H +#define TAGLIB_STRINGLIST_H + +#include "tstring.h" +#include "tlist.h" +#include "tbytevectorlist.h" + +#include + +namespace TagLib { + + //! A list of strings + + /*! + * This is a spcialization of the List class with some members convention for + * string operations. + */ + + class StringList : public List + { + public: + + /*! + * Constructs an empty StringList. + */ + StringList(); + + /*! + * Make a shallow, implicitly shared, copy of \a l. Because this is + * implicitly shared, this method is lightweight and suitable for + * pass-by-value usage. + */ + StringList(const StringList &l); + + /*! + * Constructs a StringList with \a s as a member. + */ + StringList(const String &s); + + /*! + * Makes a deep copy of the data in \a vl. + * + * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when + * used with other codecs it will simply print a warning and exit. + */ + StringList(const ByteVectorList &vl, String::Type t = String::Latin1); + + /*! + * Destroys this StringList instance. + */ + virtual ~StringList(); + + /*! + * Concatenate the list of strings into one string separated by \a separator. + */ + String toString(const String &separator = " ") const; + + /*! + * Appends \a s to the end of the list and returns a reference to the + * list. + */ + StringList &append(const String &s); + + /*! + * Appends all of the values in \a l to the end of the list and returns a + * reference to the list. + */ + StringList &append(const StringList &l); + + /*! + * Splits the String \a s into several strings at \a pattern. This will not include + * the pattern in the returned strings. + */ + static StringList split(const String &s, const String &pattern); + + private: + class StringListPrivate; + StringListPrivate *d; + }; + +} + +/*! + * \related TagLib::StringList + * Send the StringList to an output stream. + */ +std::ostream &operator<<(std::ostream &s, const TagLib::StringList &l); + +#endif diff --git a/Libraries/TagLib/Files/taglib/toolkit/unicode.cpp b/Libraries/TagLib/Files/taglib/toolkit/unicode.cpp new file mode 100644 index 000000000..b60264d91 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/unicode.cpp @@ -0,0 +1,303 @@ +/******************************************************************************* + * * + * THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB * + * AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. * + * AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. * + * * + *******************************************************************************/ + +/* + * Copyright 2001 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* + * This file has been modified by Scott Wheeler to remove + * the UTF32 conversion functions and to place the appropriate functions + * in their own C++ namespace. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "unicode.h" +#include + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +namespace Unicode { + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... six byte sequence.) + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END && source < sourceEnd) { + UTF32 ch2 = *source; + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else if ((flags == strictConversion) && (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x200000) { bytesToWrite = 4; + } else { bytesToWrite = 2; + ch = UNI_REPLACEMENT_CHAR; + } + // printf("bytes to write = %i\n", bytesToWrite); + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (ch | byteMark) & byteMask; ch >>= 6; + case 3: *--target = (ch | byteMark) & byteMask; ch >>= 6; + case 2: *--target = (ch | byteMark) & byteMask; ch >>= 6; + case 1: *--target = ch | firstByteMark[bytesToWrite]; + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + if (*source > 0xF4) return false; + } + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + if ((flags == strictConversion) && (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (ch >> halfShift) + UNI_SUR_HIGH_START; + *target++ = (ch & halfMask) + UNI_SUR_LOW_START; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ + + diff --git a/Libraries/TagLib/Files/taglib/toolkit/unicode.h b/Libraries/TagLib/Files/taglib/toolkit/unicode.h new file mode 100644 index 000000000..45d726b28 --- /dev/null +++ b/Libraries/TagLib/Files/taglib/toolkit/unicode.h @@ -0,0 +1,149 @@ +#ifndef TAGLIB_UNICODE_H +#define TAGLIB_UNICODE_H + +/******************************************************************************* + * * + * THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB * + * AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. * + * AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. * + * * + *******************************************************************************/ + +#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header + +/* + * Copyright 2001 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* + * This file has been modified by Scott Wheeler to remove + * the UTF32 conversion functions and to place the appropriate functions + * in their own C++ namespace. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: , , + or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF + +namespace Unicode { + +typedef unsigned long UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +typedef enum { + conversionOK = 0, /* conversion successful */ + sourceExhausted = 1, /* partial character in source, but hit end */ + targetExhausted = 2, /* insuff. room in target for conversion */ + sourceIllegal = 3 /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +} // namespace Unicode + +/* --------------------------------------------------------------------- */ + +#endif +#endif diff --git a/Libraries/TagLib/Info.plist b/Libraries/TagLib/Info.plist new file mode 100644 index 000000000..8ebb0ad93 --- /dev/null +++ b/Libraries/TagLib/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleName + ${PRODUCT_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.yourcocoaframework + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + + + diff --git a/Libraries/TagLib/TagLib.xcodeproj/project.pbxproj b/Libraries/TagLib/TagLib.xcodeproj/project.pbxproj new file mode 100644 index 000000000..7c661b32f --- /dev/null +++ b/Libraries/TagLib/TagLib.xcodeproj/project.pbxproj @@ -0,0 +1,865 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; + 8E75709A09F319040080F1EE /* ape-tag-format.txt in Resources */ = {isa = PBXBuildFile; fileRef = 8E75701A09F319030080F1EE /* ape-tag-format.txt */; }; + 8E75709B09F319040080F1EE /* apefooter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75701B09F319030080F1EE /* apefooter.cpp */; }; + 8E75709C09F319040080F1EE /* apefooter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75701C09F319030080F1EE /* apefooter.h */; }; + 8E75709D09F319040080F1EE /* apeitem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75701D09F319030080F1EE /* apeitem.cpp */; }; + 8E75709E09F319040080F1EE /* apeitem.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75701E09F319030080F1EE /* apeitem.h */; }; + 8E75709F09F319040080F1EE /* apetag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75701F09F319030080F1EE /* apetag.cpp */; }; + 8E7570A009F319040080F1EE /* apetag.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75702009F319030080F1EE /* apetag.h */; }; + 8E7570A109F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75702109F319030080F1EE /* Makefile.am */; }; + 8E7570A209F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75702209F319030080F1EE /* Makefile.in */; }; + 8E7570A309F319040080F1EE /* audioproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75702309F319030080F1EE /* audioproperties.cpp */; }; + 8E7570A409F319040080F1EE /* audioproperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75702409F319030080F1EE /* audioproperties.h */; }; + 8E7570A509F319040080F1EE /* fileref.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75702509F319030080F1EE /* fileref.cpp */; }; + 8E7570A609F319040080F1EE /* fileref.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75702609F319030080F1EE /* fileref.h */; }; + 8E7570A709F319040080F1EE /* flacfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75702809F319030080F1EE /* flacfile.cpp */; }; + 8E7570A809F319040080F1EE /* flacfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75702909F319030080F1EE /* flacfile.h */; }; + 8E7570A909F319040080F1EE /* flacproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75702A09F319030080F1EE /* flacproperties.cpp */; }; + 8E7570AA09F319040080F1EE /* flacproperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75702B09F319030080F1EE /* flacproperties.h */; }; + 8E7570AB09F319040080F1EE /* flactag.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75702C09F319030080F1EE /* flactag.h */; }; + 8E7570AC09F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75702D09F319030080F1EE /* Makefile.am */; }; + 8E7570AD09F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75702E09F319030080F1EE /* Makefile.in */; }; + 8E7570AE09F319040080F1EE /* combinedtag.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75703009F319030080F1EE /* combinedtag.h */; }; + 8E7570AF09F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75703109F319030080F1EE /* Makefile.am */; }; + 8E7570B009F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75703209F319030080F1EE /* Makefile.in */; }; + 8E7570B109F319040080F1EE /* mpcfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75703309F319030080F1EE /* mpcfile.cpp */; }; + 8E7570B209F319040080F1EE /* mpcfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75703409F319030080F1EE /* mpcfile.h */; }; + 8E7570B309F319040080F1EE /* mpcproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75703509F319030080F1EE /* mpcproperties.cpp */; }; + 8E7570B409F319040080F1EE /* mpcproperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75703609F319030080F1EE /* mpcproperties.h */; }; + 8E7570B509F319040080F1EE /* id3v1genres.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75703909F319030080F1EE /* id3v1genres.cpp */; }; + 8E7570B609F319040080F1EE /* id3v1genres.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75703A09F319030080F1EE /* id3v1genres.h */; }; + 8E7570B709F319040080F1EE /* id3v1tag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75703B09F319030080F1EE /* id3v1tag.cpp */; }; + 8E7570B809F319040080F1EE /* id3v1tag.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75703C09F319030080F1EE /* id3v1tag.h */; }; + 8E7570B909F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75703D09F319030080F1EE /* Makefile.am */; }; + 8E7570BA09F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75703E09F319030080F1EE /* Makefile.in */; }; + 8E7570BB09F319040080F1EE /* attachedpictureframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75704109F319030080F1EE /* attachedpictureframe.cpp */; }; + 8E7570BC09F319040080F1EE /* attachedpictureframe.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75704209F319030080F1EE /* attachedpictureframe.h */; }; + 8E7570BD09F319040080F1EE /* commentsframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75704309F319030080F1EE /* commentsframe.cpp */; }; + 8E7570BE09F319040080F1EE /* commentsframe.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75704409F319030080F1EE /* commentsframe.h */; }; + 8E7570BF09F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75704509F319030080F1EE /* Makefile.am */; }; + 8E7570C009F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75704609F319030080F1EE /* Makefile.in */; }; + 8E7570C109F319040080F1EE /* relativevolumeframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75704709F319030080F1EE /* relativevolumeframe.cpp */; }; + 8E7570C209F319040080F1EE /* relativevolumeframe.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75704809F319030080F1EE /* relativevolumeframe.h */; }; + 8E7570C309F319040080F1EE /* textidentificationframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75704909F319030080F1EE /* textidentificationframe.cpp */; }; + 8E7570C409F319040080F1EE /* textidentificationframe.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75704A09F319030080F1EE /* textidentificationframe.h */; }; + 8E7570C509F319040080F1EE /* uniquefileidentifierframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75704B09F319030080F1EE /* uniquefileidentifierframe.cpp */; }; + 8E7570C609F319040080F1EE /* uniquefileidentifierframe.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75704C09F319030080F1EE /* uniquefileidentifierframe.h */; }; + 8E7570C709F319040080F1EE /* unknownframe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75704D09F319030080F1EE /* unknownframe.cpp */; }; + 8E7570C809F319040080F1EE /* unknownframe.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75704E09F319030080F1EE /* unknownframe.h */; }; + 8E7570C909F319040080F1EE /* id3v2.4.0-frames.txt in Resources */ = {isa = PBXBuildFile; fileRef = 8E75704F09F319030080F1EE /* id3v2.4.0-frames.txt */; }; + 8E7570CA09F319040080F1EE /* id3v2.4.0-structure.txt in Resources */ = {isa = PBXBuildFile; fileRef = 8E75705009F319030080F1EE /* id3v2.4.0-structure.txt */; }; + 8E7570CB09F319040080F1EE /* id3v2extendedheader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75705109F319030080F1EE /* id3v2extendedheader.cpp */; }; + 8E7570CC09F319040080F1EE /* id3v2extendedheader.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75705209F319030080F1EE /* id3v2extendedheader.h */; }; + 8E7570CD09F319040080F1EE /* id3v2footer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75705309F319030080F1EE /* id3v2footer.cpp */; }; + 8E7570CE09F319040080F1EE /* id3v2footer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75705409F319030080F1EE /* id3v2footer.h */; }; + 8E7570CF09F319040080F1EE /* id3v2frame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75705509F319030080F1EE /* id3v2frame.cpp */; }; + 8E7570D009F319040080F1EE /* id3v2frame.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75705609F319030080F1EE /* id3v2frame.h */; }; + 8E7570D109F319040080F1EE /* id3v2framefactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75705709F319030080F1EE /* id3v2framefactory.cpp */; }; + 8E7570D209F319040080F1EE /* id3v2framefactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75705809F319030080F1EE /* id3v2framefactory.h */; }; + 8E7570D309F319040080F1EE /* id3v2header.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75705909F319030080F1EE /* id3v2header.cpp */; }; + 8E7570D409F319040080F1EE /* id3v2header.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75705A09F319030080F1EE /* id3v2header.h */; }; + 8E7570D509F319040080F1EE /* id3v2synchdata.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75705B09F319030080F1EE /* id3v2synchdata.cpp */; }; + 8E7570D609F319040080F1EE /* id3v2synchdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75705C09F319030080F1EE /* id3v2synchdata.h */; }; + 8E7570D709F319040080F1EE /* id3v2tag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75705D09F319030080F1EE /* id3v2tag.cpp */; }; + 8E7570D809F319040080F1EE /* id3v2tag.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75705E09F319030080F1EE /* id3v2tag.h */; }; + 8E7570D909F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75705F09F319030080F1EE /* Makefile.am */; }; + 8E7570DA09F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75706009F319030080F1EE /* Makefile.in */; }; + 8E7570DB09F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75706109F319030080F1EE /* Makefile.am */; }; + 8E7570DC09F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75706209F319040080F1EE /* Makefile.in */; }; + 8E7570DD09F319040080F1EE /* mpegfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75706309F319040080F1EE /* mpegfile.cpp */; }; + 8E7570DE09F319040080F1EE /* mpegfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75706409F319040080F1EE /* mpegfile.h */; }; + 8E7570DF09F319040080F1EE /* mpegheader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75706509F319040080F1EE /* mpegheader.cpp */; }; + 8E7570E009F319040080F1EE /* mpegheader.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75706609F319040080F1EE /* mpegheader.h */; }; + 8E7570E109F319040080F1EE /* mpegproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75706709F319040080F1EE /* mpegproperties.cpp */; }; + 8E7570E209F319040080F1EE /* mpegproperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75706809F319040080F1EE /* mpegproperties.h */; }; + 8E7570E309F319040080F1EE /* xingheader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75706909F319040080F1EE /* xingheader.cpp */; }; + 8E7570E409F319040080F1EE /* xingheader.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75706A09F319040080F1EE /* xingheader.h */; }; + 8E7570E509F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75706D09F319040080F1EE /* Makefile.am */; }; + 8E7570E609F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75706E09F319040080F1EE /* Makefile.in */; }; + 8E7570E709F319040080F1EE /* oggflacfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75706F09F319040080F1EE /* oggflacfile.cpp */; }; + 8E7570E809F319040080F1EE /* oggflacfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75707009F319040080F1EE /* oggflacfile.h */; }; + 8E7570E909F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75707109F319040080F1EE /* Makefile.am */; }; + 8E7570EA09F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75707209F319040080F1EE /* Makefile.in */; }; + 8E7570EB09F319040080F1EE /* oggfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75707309F319040080F1EE /* oggfile.cpp */; }; + 8E7570EC09F319040080F1EE /* oggfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75707409F319040080F1EE /* oggfile.h */; }; + 8E7570ED09F319040080F1EE /* oggpage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75707509F319040080F1EE /* oggpage.cpp */; }; + 8E7570EE09F319040080F1EE /* oggpage.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75707609F319040080F1EE /* oggpage.h */; }; + 8E7570EF09F319040080F1EE /* oggpageheader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75707709F319040080F1EE /* oggpageheader.cpp */; }; + 8E7570F009F319040080F1EE /* oggpageheader.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75707809F319040080F1EE /* oggpageheader.h */; }; + 8E7570F109F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75707A09F319040080F1EE /* Makefile.am */; }; + 8E7570F209F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75707B09F319040080F1EE /* Makefile.in */; }; + 8E7570F309F319040080F1EE /* vorbisfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75707C09F319040080F1EE /* vorbisfile.cpp */; }; + 8E7570F409F319040080F1EE /* vorbisfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75707D09F319040080F1EE /* vorbisfile.h */; }; + 8E7570F509F319040080F1EE /* vorbisproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75707E09F319040080F1EE /* vorbisproperties.cpp */; }; + 8E7570F609F319040080F1EE /* vorbisproperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75707F09F319040080F1EE /* vorbisproperties.h */; }; + 8E7570F709F319040080F1EE /* xiphcomment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75708009F319040080F1EE /* xiphcomment.cpp */; }; + 8E7570F809F319040080F1EE /* xiphcomment.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75708109F319040080F1EE /* xiphcomment.h */; }; + 8E7570F909F319040080F1EE /* tag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75708209F319040080F1EE /* tag.cpp */; }; + 8E7570FA09F319040080F1EE /* tag.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75708309F319040080F1EE /* tag.h */; }; + 8E7570FB09F319040080F1EE /* Makefile.am in Resources */ = {isa = PBXBuildFile; fileRef = 8E75708509F319040080F1EE /* Makefile.am */; }; + 8E7570FC09F319040080F1EE /* Makefile.in in Resources */ = {isa = PBXBuildFile; fileRef = 8E75708609F319040080F1EE /* Makefile.in */; }; + 8E7570FD09F319040080F1EE /* taglib.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75708709F319040080F1EE /* taglib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E7570FE09F319040080F1EE /* tbytevector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75708809F319040080F1EE /* tbytevector.cpp */; }; + 8E7570FF09F319040080F1EE /* tbytevector.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75708909F319040080F1EE /* tbytevector.h */; }; + 8E75710009F319040080F1EE /* tbytevectorlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75708A09F319040080F1EE /* tbytevectorlist.cpp */; }; + 8E75710109F319040080F1EE /* tbytevectorlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75708B09F319040080F1EE /* tbytevectorlist.h */; }; + 8E75710209F319040080F1EE /* tdebug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75708C09F319040080F1EE /* tdebug.cpp */; }; + 8E75710309F319040080F1EE /* tdebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75708D09F319040080F1EE /* tdebug.h */; }; + 8E75710409F319040080F1EE /* tfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75708E09F319040080F1EE /* tfile.cpp */; }; + 8E75710509F319040080F1EE /* tfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75708F09F319040080F1EE /* tfile.h */; }; + 8E75710609F319040080F1EE /* tlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75709009F319040080F1EE /* tlist.h */; }; + 8E75710709F319040080F1EE /* tlist.tcc in Resources */ = {isa = PBXBuildFile; fileRef = 8E75709109F319040080F1EE /* tlist.tcc */; }; + 8E75710809F319040080F1EE /* tmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75709209F319040080F1EE /* tmap.h */; }; + 8E75710909F319040080F1EE /* tmap.tcc in Resources */ = {isa = PBXBuildFile; fileRef = 8E75709309F319040080F1EE /* tmap.tcc */; }; + 8E75710A09F319040080F1EE /* tstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75709409F319040080F1EE /* tstring.cpp */; }; + 8E75710B09F319040080F1EE /* tstring.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75709509F319040080F1EE /* tstring.h */; }; + 8E75710C09F319040080F1EE /* tstringlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75709609F319040080F1EE /* tstringlist.cpp */; }; + 8E75710D09F319040080F1EE /* tstringlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75709709F319040080F1EE /* tstringlist.h */; }; + 8E75710E09F319040080F1EE /* unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75709809F319040080F1EE /* unicode.cpp */; }; + 8E75710F09F319040080F1EE /* unicode.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75709909F319040080F1EE /* unicode.h */; }; + 8E75711309F3190D0080F1EE /* tag_c.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E75711109F3190D0080F1EE /* tag_c.cpp */; }; + 8E75711409F3190D0080F1EE /* tag_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75711209F3190D0080F1EE /* tag_c.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E75712209F319570080F1EE /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E75712109F319570080F1EE /* config.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildStyle section */ + 014CEA440018CDF011CA2923 /* Debug */ = { + isa = PBXBuildStyle; + buildSettings = { + }; + name = Debug; + }; + 014CEA450018CDF011CA2923 /* Release */ = { + isa = PBXBuildStyle; + buildSettings = { + }; + name = Release; + }; +/* End PBXBuildStyle section */ + +/* Begin PBXFileReference section */ + 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8DC2EF5B0486A6940098B216 /* TagLib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TagLib.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8E75701A09F319030080F1EE /* ape-tag-format.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "ape-tag-format.txt"; sourceTree = ""; }; + 8E75701B09F319030080F1EE /* apefooter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = apefooter.cpp; sourceTree = ""; }; + 8E75701C09F319030080F1EE /* apefooter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = apefooter.h; sourceTree = ""; }; + 8E75701D09F319030080F1EE /* apeitem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = apeitem.cpp; sourceTree = ""; }; + 8E75701E09F319030080F1EE /* apeitem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = apeitem.h; sourceTree = ""; }; + 8E75701F09F319030080F1EE /* apetag.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = apetag.cpp; sourceTree = ""; }; + 8E75702009F319030080F1EE /* apetag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = apetag.h; sourceTree = ""; }; + 8E75702109F319030080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75702209F319030080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75702309F319030080F1EE /* audioproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audioproperties.cpp; path = Files/taglib/audioproperties.cpp; sourceTree = ""; }; + 8E75702409F319030080F1EE /* audioproperties.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = audioproperties.h; path = Files/taglib/audioproperties.h; sourceTree = ""; }; + 8E75702509F319030080F1EE /* fileref.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = fileref.cpp; path = Files/taglib/fileref.cpp; sourceTree = ""; }; + 8E75702609F319030080F1EE /* fileref.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = fileref.h; path = Files/taglib/fileref.h; sourceTree = ""; }; + 8E75702809F319030080F1EE /* flacfile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = flacfile.cpp; sourceTree = ""; }; + 8E75702909F319030080F1EE /* flacfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = flacfile.h; sourceTree = ""; }; + 8E75702A09F319030080F1EE /* flacproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = flacproperties.cpp; sourceTree = ""; }; + 8E75702B09F319030080F1EE /* flacproperties.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = flacproperties.h; sourceTree = ""; }; + 8E75702C09F319030080F1EE /* flactag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = flactag.h; sourceTree = ""; }; + 8E75702D09F319030080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75702E09F319030080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75703009F319030080F1EE /* combinedtag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = combinedtag.h; sourceTree = ""; }; + 8E75703109F319030080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75703209F319030080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75703309F319030080F1EE /* mpcfile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mpcfile.cpp; sourceTree = ""; }; + 8E75703409F319030080F1EE /* mpcfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mpcfile.h; sourceTree = ""; }; + 8E75703509F319030080F1EE /* mpcproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mpcproperties.cpp; sourceTree = ""; }; + 8E75703609F319030080F1EE /* mpcproperties.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mpcproperties.h; sourceTree = ""; }; + 8E75703909F319030080F1EE /* id3v1genres.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v1genres.cpp; sourceTree = ""; }; + 8E75703A09F319030080F1EE /* id3v1genres.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v1genres.h; sourceTree = ""; }; + 8E75703B09F319030080F1EE /* id3v1tag.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v1tag.cpp; sourceTree = ""; }; + 8E75703C09F319030080F1EE /* id3v1tag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v1tag.h; sourceTree = ""; }; + 8E75703D09F319030080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75703E09F319030080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75704109F319030080F1EE /* attachedpictureframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = attachedpictureframe.cpp; sourceTree = ""; }; + 8E75704209F319030080F1EE /* attachedpictureframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = attachedpictureframe.h; sourceTree = ""; }; + 8E75704309F319030080F1EE /* commentsframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = commentsframe.cpp; sourceTree = ""; }; + 8E75704409F319030080F1EE /* commentsframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = commentsframe.h; sourceTree = ""; }; + 8E75704509F319030080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75704609F319030080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75704709F319030080F1EE /* relativevolumeframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = relativevolumeframe.cpp; sourceTree = ""; }; + 8E75704809F319030080F1EE /* relativevolumeframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = relativevolumeframe.h; sourceTree = ""; }; + 8E75704909F319030080F1EE /* textidentificationframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = textidentificationframe.cpp; sourceTree = ""; }; + 8E75704A09F319030080F1EE /* textidentificationframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = textidentificationframe.h; sourceTree = ""; }; + 8E75704B09F319030080F1EE /* uniquefileidentifierframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = uniquefileidentifierframe.cpp; sourceTree = ""; }; + 8E75704C09F319030080F1EE /* uniquefileidentifierframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = uniquefileidentifierframe.h; sourceTree = ""; }; + 8E75704D09F319030080F1EE /* unknownframe.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = unknownframe.cpp; sourceTree = ""; }; + 8E75704E09F319030080F1EE /* unknownframe.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = unknownframe.h; sourceTree = ""; }; + 8E75704F09F319030080F1EE /* id3v2.4.0-frames.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "id3v2.4.0-frames.txt"; sourceTree = ""; }; + 8E75705009F319030080F1EE /* id3v2.4.0-structure.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "id3v2.4.0-structure.txt"; sourceTree = ""; }; + 8E75705109F319030080F1EE /* id3v2extendedheader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v2extendedheader.cpp; sourceTree = ""; }; + 8E75705209F319030080F1EE /* id3v2extendedheader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v2extendedheader.h; sourceTree = ""; }; + 8E75705309F319030080F1EE /* id3v2footer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v2footer.cpp; sourceTree = ""; }; + 8E75705409F319030080F1EE /* id3v2footer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v2footer.h; sourceTree = ""; }; + 8E75705509F319030080F1EE /* id3v2frame.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v2frame.cpp; sourceTree = ""; }; + 8E75705609F319030080F1EE /* id3v2frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v2frame.h; sourceTree = ""; }; + 8E75705709F319030080F1EE /* id3v2framefactory.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v2framefactory.cpp; sourceTree = ""; }; + 8E75705809F319030080F1EE /* id3v2framefactory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v2framefactory.h; sourceTree = ""; }; + 8E75705909F319030080F1EE /* id3v2header.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v2header.cpp; sourceTree = ""; }; + 8E75705A09F319030080F1EE /* id3v2header.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v2header.h; sourceTree = ""; }; + 8E75705B09F319030080F1EE /* id3v2synchdata.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v2synchdata.cpp; sourceTree = ""; }; + 8E75705C09F319030080F1EE /* id3v2synchdata.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v2synchdata.h; sourceTree = ""; }; + 8E75705D09F319030080F1EE /* id3v2tag.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = id3v2tag.cpp; sourceTree = ""; }; + 8E75705E09F319030080F1EE /* id3v2tag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id3v2tag.h; sourceTree = ""; }; + 8E75705F09F319030080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75706009F319030080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75706109F319030080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75706209F319040080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75706309F319040080F1EE /* mpegfile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mpegfile.cpp; sourceTree = ""; }; + 8E75706409F319040080F1EE /* mpegfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mpegfile.h; sourceTree = ""; }; + 8E75706509F319040080F1EE /* mpegheader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mpegheader.cpp; sourceTree = ""; }; + 8E75706609F319040080F1EE /* mpegheader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mpegheader.h; sourceTree = ""; }; + 8E75706709F319040080F1EE /* mpegproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = mpegproperties.cpp; sourceTree = ""; }; + 8E75706809F319040080F1EE /* mpegproperties.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mpegproperties.h; sourceTree = ""; }; + 8E75706909F319040080F1EE /* xingheader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = xingheader.cpp; sourceTree = ""; }; + 8E75706A09F319040080F1EE /* xingheader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = xingheader.h; sourceTree = ""; }; + 8E75706D09F319040080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75706E09F319040080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75706F09F319040080F1EE /* oggflacfile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = oggflacfile.cpp; sourceTree = ""; }; + 8E75707009F319040080F1EE /* oggflacfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = oggflacfile.h; sourceTree = ""; }; + 8E75707109F319040080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75707209F319040080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75707309F319040080F1EE /* oggfile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = oggfile.cpp; sourceTree = ""; }; + 8E75707409F319040080F1EE /* oggfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = oggfile.h; sourceTree = ""; }; + 8E75707509F319040080F1EE /* oggpage.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = oggpage.cpp; sourceTree = ""; }; + 8E75707609F319040080F1EE /* oggpage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = oggpage.h; sourceTree = ""; }; + 8E75707709F319040080F1EE /* oggpageheader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = oggpageheader.cpp; sourceTree = ""; }; + 8E75707809F319040080F1EE /* oggpageheader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = oggpageheader.h; sourceTree = ""; }; + 8E75707A09F319040080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75707B09F319040080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75707C09F319040080F1EE /* vorbisfile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = vorbisfile.cpp; sourceTree = ""; }; + 8E75707D09F319040080F1EE /* vorbisfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vorbisfile.h; sourceTree = ""; }; + 8E75707E09F319040080F1EE /* vorbisproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = vorbisproperties.cpp; sourceTree = ""; }; + 8E75707F09F319040080F1EE /* vorbisproperties.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vorbisproperties.h; sourceTree = ""; }; + 8E75708009F319040080F1EE /* xiphcomment.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = xiphcomment.cpp; sourceTree = ""; }; + 8E75708109F319040080F1EE /* xiphcomment.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = xiphcomment.h; sourceTree = ""; }; + 8E75708209F319040080F1EE /* tag.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = tag.cpp; path = Files/taglib/tag.cpp; sourceTree = ""; }; + 8E75708309F319040080F1EE /* tag.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = tag.h; path = Files/taglib/tag.h; sourceTree = ""; }; + 8E75708509F319040080F1EE /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = ""; }; + 8E75708609F319040080F1EE /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = ""; }; + 8E75708709F319040080F1EE /* taglib.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = taglib.h; sourceTree = ""; }; + 8E75708809F319040080F1EE /* tbytevector.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tbytevector.cpp; sourceTree = ""; }; + 8E75708909F319040080F1EE /* tbytevector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tbytevector.h; sourceTree = ""; }; + 8E75708A09F319040080F1EE /* tbytevectorlist.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tbytevectorlist.cpp; sourceTree = ""; }; + 8E75708B09F319040080F1EE /* tbytevectorlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tbytevectorlist.h; sourceTree = ""; }; + 8E75708C09F319040080F1EE /* tdebug.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tdebug.cpp; sourceTree = ""; }; + 8E75708D09F319040080F1EE /* tdebug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tdebug.h; sourceTree = ""; }; + 8E75708E09F319040080F1EE /* tfile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tfile.cpp; sourceTree = ""; }; + 8E75708F09F319040080F1EE /* tfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tfile.h; sourceTree = ""; }; + 8E75709009F319040080F1EE /* tlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tlist.h; sourceTree = ""; }; + 8E75709109F319040080F1EE /* tlist.tcc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = tlist.tcc; sourceTree = ""; }; + 8E75709209F319040080F1EE /* tmap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tmap.h; sourceTree = ""; }; + 8E75709309F319040080F1EE /* tmap.tcc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = tmap.tcc; sourceTree = ""; }; + 8E75709409F319040080F1EE /* tstring.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tstring.cpp; sourceTree = ""; }; + 8E75709509F319040080F1EE /* tstring.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tstring.h; sourceTree = ""; }; + 8E75709609F319040080F1EE /* tstringlist.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tstringlist.cpp; sourceTree = ""; }; + 8E75709709F319040080F1EE /* tstringlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tstringlist.h; sourceTree = ""; }; + 8E75709809F319040080F1EE /* unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = unicode.cpp; sourceTree = ""; }; + 8E75709909F319040080F1EE /* unicode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = unicode.h; sourceTree = ""; }; + 8E75711109F3190D0080F1EE /* tag_c.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = tag_c.cpp; sourceTree = ""; }; + 8E75711209F3190D0080F1EE /* tag_c.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tag_c.h; sourceTree = ""; }; + 8E75712109F319570080F1EE /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = config.h; path = Files/config.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DC2EF560486A6940098B216 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DFFF38A50411DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 8DC2EF5B0486A6940098B216 /* TagLib.framework */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* TagLib */ = { + isa = PBXGroup; + children = ( + 8E75700C09F318D70080F1EE /* Source */, + 089C1665FE841158C02AAC07 /* Resources */, + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + 034768DFFF38A50411DB9C8B /* Products */, + ); + name = TagLib; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */, + 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C1665FE841158C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 8DC2EF5A0486A6940098B216 /* Info.plist */, + 089C1666FE841158C02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 8E75700C09F318D70080F1EE /* Source */ = { + isa = PBXGroup; + children = ( + 8E75712109F319570080F1EE /* config.h */, + 8E75711009F3190D0080F1EE /* c */, + 8E75701909F319030080F1EE /* ape */, + 8E75702309F319030080F1EE /* audioproperties.cpp */, + 8E75702409F319030080F1EE /* audioproperties.h */, + 8E75702509F319030080F1EE /* fileref.cpp */, + 8E75702609F319030080F1EE /* fileref.h */, + 8E75702709F319030080F1EE /* flac */, + 8E75702F09F319030080F1EE /* mpc */, + 8E75703709F319030080F1EE /* mpeg */, + 8E75706B09F319040080F1EE /* ogg */, + 8E75708209F319040080F1EE /* tag.cpp */, + 8E75708309F319040080F1EE /* tag.h */, + 8E75708409F319040080F1EE /* toolkit */, + ); + name = Source; + sourceTree = ""; + }; + 8E75701909F319030080F1EE /* ape */ = { + isa = PBXGroup; + children = ( + 8E75701A09F319030080F1EE /* ape-tag-format.txt */, + 8E75701B09F319030080F1EE /* apefooter.cpp */, + 8E75701C09F319030080F1EE /* apefooter.h */, + 8E75701D09F319030080F1EE /* apeitem.cpp */, + 8E75701E09F319030080F1EE /* apeitem.h */, + 8E75701F09F319030080F1EE /* apetag.cpp */, + 8E75702009F319030080F1EE /* apetag.h */, + 8E75702109F319030080F1EE /* Makefile.am */, + 8E75702209F319030080F1EE /* Makefile.in */, + ); + name = ape; + path = Files/taglib/ape; + sourceTree = ""; + }; + 8E75702709F319030080F1EE /* flac */ = { + isa = PBXGroup; + children = ( + 8E75702809F319030080F1EE /* flacfile.cpp */, + 8E75702909F319030080F1EE /* flacfile.h */, + 8E75702A09F319030080F1EE /* flacproperties.cpp */, + 8E75702B09F319030080F1EE /* flacproperties.h */, + 8E75702C09F319030080F1EE /* flactag.h */, + 8E75702D09F319030080F1EE /* Makefile.am */, + 8E75702E09F319030080F1EE /* Makefile.in */, + ); + name = flac; + path = Files/taglib/flac; + sourceTree = ""; + }; + 8E75702F09F319030080F1EE /* mpc */ = { + isa = PBXGroup; + children = ( + 8E75703009F319030080F1EE /* combinedtag.h */, + 8E75703109F319030080F1EE /* Makefile.am */, + 8E75703209F319030080F1EE /* Makefile.in */, + 8E75703309F319030080F1EE /* mpcfile.cpp */, + 8E75703409F319030080F1EE /* mpcfile.h */, + 8E75703509F319030080F1EE /* mpcproperties.cpp */, + 8E75703609F319030080F1EE /* mpcproperties.h */, + ); + name = mpc; + path = Files/taglib/mpc; + sourceTree = ""; + }; + 8E75703709F319030080F1EE /* mpeg */ = { + isa = PBXGroup; + children = ( + 8E75703809F319030080F1EE /* id3v1 */, + 8E75703F09F319030080F1EE /* id3v2 */, + 8E75706109F319030080F1EE /* Makefile.am */, + 8E75706209F319040080F1EE /* Makefile.in */, + 8E75706309F319040080F1EE /* mpegfile.cpp */, + 8E75706409F319040080F1EE /* mpegfile.h */, + 8E75706509F319040080F1EE /* mpegheader.cpp */, + 8E75706609F319040080F1EE /* mpegheader.h */, + 8E75706709F319040080F1EE /* mpegproperties.cpp */, + 8E75706809F319040080F1EE /* mpegproperties.h */, + 8E75706909F319040080F1EE /* xingheader.cpp */, + 8E75706A09F319040080F1EE /* xingheader.h */, + ); + name = mpeg; + path = Files/taglib/mpeg; + sourceTree = ""; + }; + 8E75703809F319030080F1EE /* id3v1 */ = { + isa = PBXGroup; + children = ( + 8E75703909F319030080F1EE /* id3v1genres.cpp */, + 8E75703A09F319030080F1EE /* id3v1genres.h */, + 8E75703B09F319030080F1EE /* id3v1tag.cpp */, + 8E75703C09F319030080F1EE /* id3v1tag.h */, + 8E75703D09F319030080F1EE /* Makefile.am */, + 8E75703E09F319030080F1EE /* Makefile.in */, + ); + path = id3v1; + sourceTree = ""; + }; + 8E75703F09F319030080F1EE /* id3v2 */ = { + isa = PBXGroup; + children = ( + 8E75704009F319030080F1EE /* frames */, + 8E75704F09F319030080F1EE /* id3v2.4.0-frames.txt */, + 8E75705009F319030080F1EE /* id3v2.4.0-structure.txt */, + 8E75705109F319030080F1EE /* id3v2extendedheader.cpp */, + 8E75705209F319030080F1EE /* id3v2extendedheader.h */, + 8E75705309F319030080F1EE /* id3v2footer.cpp */, + 8E75705409F319030080F1EE /* id3v2footer.h */, + 8E75705509F319030080F1EE /* id3v2frame.cpp */, + 8E75705609F319030080F1EE /* id3v2frame.h */, + 8E75705709F319030080F1EE /* id3v2framefactory.cpp */, + 8E75705809F319030080F1EE /* id3v2framefactory.h */, + 8E75705909F319030080F1EE /* id3v2header.cpp */, + 8E75705A09F319030080F1EE /* id3v2header.h */, + 8E75705B09F319030080F1EE /* id3v2synchdata.cpp */, + 8E75705C09F319030080F1EE /* id3v2synchdata.h */, + 8E75705D09F319030080F1EE /* id3v2tag.cpp */, + 8E75705E09F319030080F1EE /* id3v2tag.h */, + 8E75705F09F319030080F1EE /* Makefile.am */, + 8E75706009F319030080F1EE /* Makefile.in */, + ); + path = id3v2; + sourceTree = ""; + }; + 8E75704009F319030080F1EE /* frames */ = { + isa = PBXGroup; + children = ( + 8E75704109F319030080F1EE /* attachedpictureframe.cpp */, + 8E75704209F319030080F1EE /* attachedpictureframe.h */, + 8E75704309F319030080F1EE /* commentsframe.cpp */, + 8E75704409F319030080F1EE /* commentsframe.h */, + 8E75704509F319030080F1EE /* Makefile.am */, + 8E75704609F319030080F1EE /* Makefile.in */, + 8E75704709F319030080F1EE /* relativevolumeframe.cpp */, + 8E75704809F319030080F1EE /* relativevolumeframe.h */, + 8E75704909F319030080F1EE /* textidentificationframe.cpp */, + 8E75704A09F319030080F1EE /* textidentificationframe.h */, + 8E75704B09F319030080F1EE /* uniquefileidentifierframe.cpp */, + 8E75704C09F319030080F1EE /* uniquefileidentifierframe.h */, + 8E75704D09F319030080F1EE /* unknownframe.cpp */, + 8E75704E09F319030080F1EE /* unknownframe.h */, + ); + path = frames; + sourceTree = ""; + }; + 8E75706B09F319040080F1EE /* ogg */ = { + isa = PBXGroup; + children = ( + 8E75706C09F319040080F1EE /* flac */, + 8E75707109F319040080F1EE /* Makefile.am */, + 8E75707209F319040080F1EE /* Makefile.in */, + 8E75707309F319040080F1EE /* oggfile.cpp */, + 8E75707409F319040080F1EE /* oggfile.h */, + 8E75707509F319040080F1EE /* oggpage.cpp */, + 8E75707609F319040080F1EE /* oggpage.h */, + 8E75707709F319040080F1EE /* oggpageheader.cpp */, + 8E75707809F319040080F1EE /* oggpageheader.h */, + 8E75707909F319040080F1EE /* vorbis */, + 8E75708009F319040080F1EE /* xiphcomment.cpp */, + 8E75708109F319040080F1EE /* xiphcomment.h */, + ); + name = ogg; + path = Files/taglib/ogg; + sourceTree = ""; + }; + 8E75706C09F319040080F1EE /* flac */ = { + isa = PBXGroup; + children = ( + 8E75706D09F319040080F1EE /* Makefile.am */, + 8E75706E09F319040080F1EE /* Makefile.in */, + 8E75706F09F319040080F1EE /* oggflacfile.cpp */, + 8E75707009F319040080F1EE /* oggflacfile.h */, + ); + path = flac; + sourceTree = ""; + }; + 8E75707909F319040080F1EE /* vorbis */ = { + isa = PBXGroup; + children = ( + 8E75707A09F319040080F1EE /* Makefile.am */, + 8E75707B09F319040080F1EE /* Makefile.in */, + 8E75707C09F319040080F1EE /* vorbisfile.cpp */, + 8E75707D09F319040080F1EE /* vorbisfile.h */, + 8E75707E09F319040080F1EE /* vorbisproperties.cpp */, + 8E75707F09F319040080F1EE /* vorbisproperties.h */, + ); + path = vorbis; + sourceTree = ""; + }; + 8E75708409F319040080F1EE /* toolkit */ = { + isa = PBXGroup; + children = ( + 8E75708509F319040080F1EE /* Makefile.am */, + 8E75708609F319040080F1EE /* Makefile.in */, + 8E75708709F319040080F1EE /* taglib.h */, + 8E75708809F319040080F1EE /* tbytevector.cpp */, + 8E75708909F319040080F1EE /* tbytevector.h */, + 8E75708A09F319040080F1EE /* tbytevectorlist.cpp */, + 8E75708B09F319040080F1EE /* tbytevectorlist.h */, + 8E75708C09F319040080F1EE /* tdebug.cpp */, + 8E75708D09F319040080F1EE /* tdebug.h */, + 8E75708E09F319040080F1EE /* tfile.cpp */, + 8E75708F09F319040080F1EE /* tfile.h */, + 8E75709009F319040080F1EE /* tlist.h */, + 8E75709109F319040080F1EE /* tlist.tcc */, + 8E75709209F319040080F1EE /* tmap.h */, + 8E75709309F319040080F1EE /* tmap.tcc */, + 8E75709409F319040080F1EE /* tstring.cpp */, + 8E75709509F319040080F1EE /* tstring.h */, + 8E75709609F319040080F1EE /* tstringlist.cpp */, + 8E75709709F319040080F1EE /* tstringlist.h */, + 8E75709809F319040080F1EE /* unicode.cpp */, + 8E75709909F319040080F1EE /* unicode.h */, + ); + name = toolkit; + path = Files/taglib/toolkit; + sourceTree = ""; + }; + 8E75711009F3190D0080F1EE /* c */ = { + isa = PBXGroup; + children = ( + 8E75711109F3190D0080F1EE /* tag_c.cpp */, + 8E75711209F3190D0080F1EE /* tag_c.h */, + ); + name = c; + path = Files/bindings/c; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8DC2EF500486A6940098B216 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E75709C09F319040080F1EE /* apefooter.h in Headers */, + 8E75709E09F319040080F1EE /* apeitem.h in Headers */, + 8E7570A009F319040080F1EE /* apetag.h in Headers */, + 8E7570A409F319040080F1EE /* audioproperties.h in Headers */, + 8E7570A609F319040080F1EE /* fileref.h in Headers */, + 8E7570A809F319040080F1EE /* flacfile.h in Headers */, + 8E7570AA09F319040080F1EE /* flacproperties.h in Headers */, + 8E7570AB09F319040080F1EE /* flactag.h in Headers */, + 8E7570AE09F319040080F1EE /* combinedtag.h in Headers */, + 8E7570B209F319040080F1EE /* mpcfile.h in Headers */, + 8E7570B409F319040080F1EE /* mpcproperties.h in Headers */, + 8E7570B609F319040080F1EE /* id3v1genres.h in Headers */, + 8E7570B809F319040080F1EE /* id3v1tag.h in Headers */, + 8E7570BC09F319040080F1EE /* attachedpictureframe.h in Headers */, + 8E7570BE09F319040080F1EE /* commentsframe.h in Headers */, + 8E7570C209F319040080F1EE /* relativevolumeframe.h in Headers */, + 8E7570C409F319040080F1EE /* textidentificationframe.h in Headers */, + 8E7570C609F319040080F1EE /* uniquefileidentifierframe.h in Headers */, + 8E7570C809F319040080F1EE /* unknownframe.h in Headers */, + 8E7570CC09F319040080F1EE /* id3v2extendedheader.h in Headers */, + 8E7570CE09F319040080F1EE /* id3v2footer.h in Headers */, + 8E7570D009F319040080F1EE /* id3v2frame.h in Headers */, + 8E7570D209F319040080F1EE /* id3v2framefactory.h in Headers */, + 8E7570D409F319040080F1EE /* id3v2header.h in Headers */, + 8E7570D609F319040080F1EE /* id3v2synchdata.h in Headers */, + 8E7570D809F319040080F1EE /* id3v2tag.h in Headers */, + 8E7570DE09F319040080F1EE /* mpegfile.h in Headers */, + 8E7570E009F319040080F1EE /* mpegheader.h in Headers */, + 8E7570E209F319040080F1EE /* mpegproperties.h in Headers */, + 8E7570E409F319040080F1EE /* xingheader.h in Headers */, + 8E7570E809F319040080F1EE /* oggflacfile.h in Headers */, + 8E7570EC09F319040080F1EE /* oggfile.h in Headers */, + 8E7570EE09F319040080F1EE /* oggpage.h in Headers */, + 8E7570F009F319040080F1EE /* oggpageheader.h in Headers */, + 8E7570F409F319040080F1EE /* vorbisfile.h in Headers */, + 8E7570F609F319040080F1EE /* vorbisproperties.h in Headers */, + 8E7570F809F319040080F1EE /* xiphcomment.h in Headers */, + 8E7570FA09F319040080F1EE /* tag.h in Headers */, + 8E7570FD09F319040080F1EE /* taglib.h in Headers */, + 8E7570FF09F319040080F1EE /* tbytevector.h in Headers */, + 8E75710109F319040080F1EE /* tbytevectorlist.h in Headers */, + 8E75710309F319040080F1EE /* tdebug.h in Headers */, + 8E75710509F319040080F1EE /* tfile.h in Headers */, + 8E75710609F319040080F1EE /* tlist.h in Headers */, + 8E75710809F319040080F1EE /* tmap.h in Headers */, + 8E75710B09F319040080F1EE /* tstring.h in Headers */, + 8E75710D09F319040080F1EE /* tstringlist.h in Headers */, + 8E75710F09F319040080F1EE /* unicode.h in Headers */, + 8E75711409F3190D0080F1EE /* tag_c.h in Headers */, + 8E75712209F319570080F1EE /* config.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8DC2EF4F0486A6940098B216 /* TagLib */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "TagLib" */; + buildPhases = ( + 8DC2EF500486A6940098B216 /* Headers */, + 8DC2EF520486A6940098B216 /* Resources */, + 8DC2EF540486A6940098B216 /* Sources */, + 8DC2EF560486A6940098B216 /* Frameworks */, + ); + buildRules = ( + ); + buildSettings = { + }; + dependencies = ( + ); + name = TagLib; + productInstallPath = "$(HOME)/Library/Frameworks"; + productName = TagLib; + productReference = 8DC2EF5B0486A6940098B216 /* TagLib.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "TagLib" */; + buildSettings = { + }; + buildStyles = ( + 014CEA440018CDF011CA2923 /* Debug */, + 014CEA450018CDF011CA2923 /* Release */, + ); + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* TagLib */; + productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; + projectDirPath = ""; + targets = ( + 8DC2EF4F0486A6940098B216 /* TagLib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8DC2EF520486A6940098B216 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */, + 8E75709A09F319040080F1EE /* ape-tag-format.txt in Resources */, + 8E7570A109F319040080F1EE /* Makefile.am in Resources */, + 8E7570A209F319040080F1EE /* Makefile.in in Resources */, + 8E7570AC09F319040080F1EE /* Makefile.am in Resources */, + 8E7570AD09F319040080F1EE /* Makefile.in in Resources */, + 8E7570AF09F319040080F1EE /* Makefile.am in Resources */, + 8E7570B009F319040080F1EE /* Makefile.in in Resources */, + 8E7570B909F319040080F1EE /* Makefile.am in Resources */, + 8E7570BA09F319040080F1EE /* Makefile.in in Resources */, + 8E7570BF09F319040080F1EE /* Makefile.am in Resources */, + 8E7570C009F319040080F1EE /* Makefile.in in Resources */, + 8E7570C909F319040080F1EE /* id3v2.4.0-frames.txt in Resources */, + 8E7570CA09F319040080F1EE /* id3v2.4.0-structure.txt in Resources */, + 8E7570D909F319040080F1EE /* Makefile.am in Resources */, + 8E7570DA09F319040080F1EE /* Makefile.in in Resources */, + 8E7570DB09F319040080F1EE /* Makefile.am in Resources */, + 8E7570DC09F319040080F1EE /* Makefile.in in Resources */, + 8E7570E509F319040080F1EE /* Makefile.am in Resources */, + 8E7570E609F319040080F1EE /* Makefile.in in Resources */, + 8E7570E909F319040080F1EE /* Makefile.am in Resources */, + 8E7570EA09F319040080F1EE /* Makefile.in in Resources */, + 8E7570F109F319040080F1EE /* Makefile.am in Resources */, + 8E7570F209F319040080F1EE /* Makefile.in in Resources */, + 8E7570FB09F319040080F1EE /* Makefile.am in Resources */, + 8E7570FC09F319040080F1EE /* Makefile.in in Resources */, + 8E75710709F319040080F1EE /* tlist.tcc in Resources */, + 8E75710909F319040080F1EE /* tmap.tcc in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DC2EF540486A6940098B216 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E75709B09F319040080F1EE /* apefooter.cpp in Sources */, + 8E75709D09F319040080F1EE /* apeitem.cpp in Sources */, + 8E75709F09F319040080F1EE /* apetag.cpp in Sources */, + 8E7570A309F319040080F1EE /* audioproperties.cpp in Sources */, + 8E7570A509F319040080F1EE /* fileref.cpp in Sources */, + 8E7570A709F319040080F1EE /* flacfile.cpp in Sources */, + 8E7570A909F319040080F1EE /* flacproperties.cpp in Sources */, + 8E7570B109F319040080F1EE /* mpcfile.cpp in Sources */, + 8E7570B309F319040080F1EE /* mpcproperties.cpp in Sources */, + 8E7570B509F319040080F1EE /* id3v1genres.cpp in Sources */, + 8E7570B709F319040080F1EE /* id3v1tag.cpp in Sources */, + 8E7570BB09F319040080F1EE /* attachedpictureframe.cpp in Sources */, + 8E7570BD09F319040080F1EE /* commentsframe.cpp in Sources */, + 8E7570C109F319040080F1EE /* relativevolumeframe.cpp in Sources */, + 8E7570C309F319040080F1EE /* textidentificationframe.cpp in Sources */, + 8E7570C509F319040080F1EE /* uniquefileidentifierframe.cpp in Sources */, + 8E7570C709F319040080F1EE /* unknownframe.cpp in Sources */, + 8E7570CB09F319040080F1EE /* id3v2extendedheader.cpp in Sources */, + 8E7570CD09F319040080F1EE /* id3v2footer.cpp in Sources */, + 8E7570CF09F319040080F1EE /* id3v2frame.cpp in Sources */, + 8E7570D109F319040080F1EE /* id3v2framefactory.cpp in Sources */, + 8E7570D309F319040080F1EE /* id3v2header.cpp in Sources */, + 8E7570D509F319040080F1EE /* id3v2synchdata.cpp in Sources */, + 8E7570D709F319040080F1EE /* id3v2tag.cpp in Sources */, + 8E7570DD09F319040080F1EE /* mpegfile.cpp in Sources */, + 8E7570DF09F319040080F1EE /* mpegheader.cpp in Sources */, + 8E7570E109F319040080F1EE /* mpegproperties.cpp in Sources */, + 8E7570E309F319040080F1EE /* xingheader.cpp in Sources */, + 8E7570E709F319040080F1EE /* oggflacfile.cpp in Sources */, + 8E7570EB09F319040080F1EE /* oggfile.cpp in Sources */, + 8E7570ED09F319040080F1EE /* oggpage.cpp in Sources */, + 8E7570EF09F319040080F1EE /* oggpageheader.cpp in Sources */, + 8E7570F309F319040080F1EE /* vorbisfile.cpp in Sources */, + 8E7570F509F319040080F1EE /* vorbisproperties.cpp in Sources */, + 8E7570F709F319040080F1EE /* xiphcomment.cpp in Sources */, + 8E7570F909F319040080F1EE /* tag.cpp in Sources */, + 8E7570FE09F319040080F1EE /* tbytevector.cpp in Sources */, + 8E75710009F319040080F1EE /* tbytevectorlist.cpp in Sources */, + 8E75710209F319040080F1EE /* tdebug.cpp in Sources */, + 8E75710409F319040080F1EE /* tfile.cpp in Sources */, + 8E75710A09F319040080F1EE /* tstring.cpp in Sources */, + 8E75710C09F319040080F1EE /* tstringlist.cpp in Sources */, + 8E75710E09F319040080F1EE /* unicode.cpp in Sources */, + 8E75711309F3190D0080F1EE /* tag_c.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C1667FE841158C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1DEB91AE08733DA50010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Frameworks"; + PRODUCT_NAME = TagLib; + WRAPPER_EXTENSION = framework; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB91AF08733DA50010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "@executable_path/../Frameworks"; + PRODUCT_NAME = TagLib; + WRAPPER_EXTENSION = framework; + }; + name = Release; + }; + 1DEB91B208733DA50010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Debug; + }; + 1DEB91B308733DA50010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "TagLib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91AE08733DA50010E9CD /* Debug */, + 1DEB91AF08733DA50010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "TagLib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91B208733DA50010E9CD /* Debug */, + 1DEB91B308733DA50010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/Libraries/WavPack/English.lproj/InfoPlist.strings b/Libraries/WavPack/English.lproj/InfoPlist.strings new file mode 100644 index 000000000..7080cf949 Binary files /dev/null and b/Libraries/WavPack/English.lproj/InfoPlist.strings differ diff --git a/Libraries/WavPack/Files/AUTHORS b/Libraries/WavPack/Files/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/Libraries/WavPack/Files/ChangeLog b/Libraries/WavPack/Files/ChangeLog new file mode 100644 index 000000000..4daae17d1 --- /dev/null +++ b/Libraries/WavPack/Files/ChangeLog @@ -0,0 +1,106 @@ + --------------------------- + Release 4.2 - April 2, 2005 + --------------------------- + + wavpack.exe (command-line encoder) - 4.2 + ---------------------------------------- + fixed: handling of wav files larger than 2 gig + improved: stereo lossless encoding speed (including "extra" mode) + added: -i option to ignore length specified in wav header + added: -w option to write APEv2 tags directly from command line + + wvunpack.exe (command-line decoder) - 4.2 + ----------------------------------------- + improved: decoding speed + + in_wv.dll (winamp plugin) - 2.2 + ------------------------------- + added: winamp media library support + improved: decoding speed + + foo_wavpack.dll (foobar plugin) - 2.2 + ------------------------------------- + improved: decoding speed + + nxWavPack.dll (Nero plugin) - 1.1 + Cool_wv4.flt (CoolEdit / Audition filter) - 2.4 + ----------------------------------------------- + fixed: handling of wav files larger than 2 gig + improved: encoding and decoding speed + + WavPack Library Source Code - 4.2 + --------------------------------- + improved: encoding and decoding speed + fixed: works correctly with 64-bit compilers + added: mode bit to open files in "streaming" mode + + + -------------------------- + Update - December 12, 2004 + -------------------------- + + WavPack_Apollo.dll (Apollo plugin) - 1.2 + ---------------------------------------- + fixed: crash when Apollo opened and WavPack plugin can't find config file + + + -------------------------------- + Release 4.1 - September 14, 2004 + -------------------------------- + + wavpack.exe (command-line encoder) - 4.1 + ---------------------------------------- + fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files + fixed: mono or multichannel files causing crash (no corruption possible) + added: third name specification for "correction" file (EAC specific) + added: -t option to preserve timestamps + added: error summary for batch mode + + wvunpack.exe (command-line decoder) - 4.1 + ----------------------------------------- + fixed: hybrid mode decoding bugs (very obscure situations) + added: -s option to dump file summary to stdout + added: -t option to preserve timestamps + added: error summary for batch mode + + wvselfx.exe (self-extraction stub) - 4.1 + ---------------------------------------- + fixed: hybrid mode decoding bugs (very obscure situations) + + in_wv.dll (winamp plugin) - 2.1 + ------------------------------- + fixed: international characters in tags display properly (UTF-8 to Ansi) + added: maximum tag data field width changed from 64 chars to 128 chars + added: new infobox items including encoder version & modes, track #, md5 + + foo_wavpack.dll (foobar plugin) - 2.1 + ------------------------------------- + added: new database items including encoder version & modes and md5 + + WavPack_Apollo.dll (Apollo plugin) - 1.1 + ---------------------------------------- + fixed: international characters in tags display properly (UTF-8 to Ansi) + + Cool_wv4.flt (CoolEdit / Audition filter) - 2.2 + ----------------------------------------------- + fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files + fixed: saving mono file causing crash (no corruption possible) + fixed: hybrid mode decoding bugs (very obscure situations) + fixed: partial saves (with "Cancel") have incorrect RIFF header if unpacked + + nxWavPack.dll (Nero plugin) - 1.0 + --------------------------------- + new + + WavPack Library Source Code - 4.1 + --------------------------------- + fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files + fixed: mono or multichannel files causing crash (no corruption possible) + fixed: hybrid mode decoding bugs (very obscure situations) + added: mode bits for determining additional encode info (extra, sfx) + added: function to return total compressed file length (including wvc) + added: function to return encoder version (1, 2, 3, or 4) + added: ability to obtain MD5 sum before decoding file (requires seek to end) + added: mode bit for determining tag type (for proper character translation) + added: ability to encode WavPack files without knowing length in advance + added: option for small "information only" version of library diff --git a/Libraries/WavPack/Files/Makefile.am b/Libraries/WavPack/Files/Makefile.am new file mode 100644 index 000000000..820a49baa --- /dev/null +++ b/Libraries/WavPack/Files/Makefile.am @@ -0,0 +1,27 @@ +AUTOMAKE_OPTIONS = foreign +bin_PROGRAMS = wavpack wvunpack + +lib_LTLIBRARIES = libwavpack.la + +wpincludedir = $(prefix)/include/wavpack + +wpinclude_HEADERS = md5.h wavpack.h wputils.h unpack3.h + +libwavpack_la_SOURCES = bits.c float.c metadata.c unpack.c unpack3.c utils.c \ + wputils.c words.c md5.c extra1.c extra2.c pack.c \ + md5.h wavpack.h wputils.h unpack3.h +libwavpack_la_CFLAGS = -DPACK -DUNPACK -DUSE_FSTREAMS -DTAGS -DSEEKING -DVER3 +libwavpack_la_LDFLAGS = -lm @ICONV_LIBS@ + +wavpack_SOURCES = wavpack.c +wavpack_CFLAGS = -DPACK +wavpack_LDFLAGS = -lm -lcurses +wavpack_LDADD = libwavpack.la + +wvunpack_SOURCES = wvunpack.c +wvunpack_CFLAGS = -DUNPACK -DUSE_FSTREAMS +wvunpack_LDFLAGS = -lm -lcurses +wvunpack_LDADD = libwavpack.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = wavpack.pc diff --git a/Libraries/WavPack/Files/NEWS b/Libraries/WavPack/Files/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/Libraries/WavPack/Files/README b/Libraries/WavPack/Files/README new file mode 100644 index 000000000..df3507acd --- /dev/null +++ b/Libraries/WavPack/Files/README @@ -0,0 +1,86 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +This package contains all the source code required to build the WavPack +command-line programs and the WavPack library and it has been tested on many +platforms. For example code using the library you might want to check some +of the plugin sources in the Windows source release. + +To build everything, type: + +1. ./autogen.sh +2. ./configure +3. make +4. make install (optionally, to install into /usr/local/bin) + +Notes: + +1. This code is designed to be much easier to port to other platforms than + the previous version of WavPack. File I/O is done with streams and all file + functions (except "fopen") are handled in a wrapper in the "utils.c" + module. The code is even written to be endian-independent and a compile + option is provided to eliminate the DOS-specific directory searches. + + To maintain compatibility on various platforms, the following conventions + are used: + + a "short" must be 16-bits + an "int" must be at least 16-bits, but may be larger + a "char" must default to signed (Watcom users take note!) + + For version 4.2 references to "long" variables were eliminated to allow + compilation on 64-bit machines. + +2. For WavPack file decoding, a library interface in "wputils.c" provides all + the functionality required for both the winamp plugin and the "wvunpack" + command-line program (including the transparent decoding of "correction" + files). There is also an alternate entry point that uses reader callbacks + for all input, although in this case it is the caller's responsibility to + to open the "correction" file. It is no longer necessary to manipulate the + WavPack structures directly; everything is handled with function calls. In + fact, a new header file called "wputils.h" can be used that hides all the + WavPack internals from the application. + +3. For WavPack file creation, the library interface in "wputils.c" provides + all the functionality for both the Audition filter and the "wavpack" + command-line program. No file I/O is performed by the library when creating + WavPack files. Instead, the user supplies a "write_block" function that + accepts completed WavPack blocks. For version 4.2 limited functionality + has been added to append APEv2 tags to WavPack files during creation. + +4. The following #define's are used to control the optimum configuration of + the library for the desired application and must be the same for the + compilation of ALL files: + + UNPACK to unpack audio samples from WavPack files + PACK to create WavPack files from raw audio data + INFO_ONLY to obtain information from WavPack files, but not audio + SEEKING to allow seeking to a specific sample index (unpack only) + USE_FSTREAMS to open WavPack files by name using fstreams (via fopen) + TAGS to read specified fields from ID3v1 and APEv2 tags and + create APEv2 tags + VER3 to handle WavPack files from versions prior to 4.0 + WIN32 required for Win32 platform + + The following files are required for various configurations: + + UNPACK or + INFO_ONLY: wputils.c unpack.c words.c bits.c metadata.c float.c + + PACK: wputils.c pack.c extra1.c extra2.c + words.c bits.c metadata.c float.c + + PACK and + UNPACK: wputils.c unpack.c pack.c extra1.c extra2.c + words.c bits.c metadata.c float.c + +5. An alternate version of this library is available specifically designed + for "resource limited" CPUs or hardware decoding. This "tiny" decoder + library works with less than 32k of code and less than 4k of data. + +6. Questions or comments should be directed to david@wavpack.com diff --git a/Libraries/WavPack/Files/autogen.sh b/Libraries/WavPack/Files/autogen.sh new file mode 100755 index 000000000..39b82fcd9 --- /dev/null +++ b/Libraries/WavPack/Files/autogen.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +touch NEWS README AUTHORS ChangeLog +aclocal +libtoolize --copy +automake --add-missing +autoconf diff --git a/Libraries/WavPack/Files/bits.c b/Libraries/WavPack/Files/bits.c new file mode 100644 index 000000000..d062d7cf1 --- /dev/null +++ b/Libraries/WavPack/Files/bits.c @@ -0,0 +1,259 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// bits.c + +// This module provides utilities to support the BitStream structure which is +// used to read and write all WavPack audio data streams. It also contains a +// wrapper for the stream I/O functions and a set of functions dealing with +// endian-ness, both for enhancing portability. Finally, a debug wrapper for +// the malloc() system is provided. + +#include "wavpack.h" + +#include +#include +#include +#include + +#if defined(WIN32) +#include +#else +#include +#endif + +////////////////////////// Bitstream functions //////////////////////////////// + +#if defined(UNPACK) || defined(INFO_ONLY) + +// Open the specified BitStream and associate with the specified buffer. + +static void bs_read (Bitstream *bs); + +void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end) +{ + bs->error = bs->sr = bs->bc = 0; + bs->ptr = (bs->buf = buffer_start) - 1; + bs->end = buffer_end; + bs->wrap = bs_read; +} + +// This function is only called from the getbit() and getbits() macros when +// the BitStream has been exhausted and more data is required. Sinve these +// bistreams no longer access files, this function simple sets an error and +// resets the buffer. + +static void bs_read (Bitstream *bs) +{ + bs->ptr = bs->buf - 1; + bs->error = 1; +} + +// This function is called to close the bitstream. It returns the number of +// full bytes actually read as bits. + +uint32_t bs_close_read (Bitstream *bs) +{ + uint32_t bytes_read; + + if (bs->bc < 8) + bs->ptr++; + + if ((bs->buf - bs->ptr) & 1) + bs->ptr++; + + bytes_read = bs->ptr - bs->buf; + CLEAR (*bs); + return bytes_read; +} + +#endif + +#ifdef PACK + +// Open the specified BitStream using the specified buffer pointers. It is +// assumed that enough buffer space has been allocated for all data that will +// be written, otherwise an error will be generated. + +static void bs_write (Bitstream *bs); + +void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end) +{ + bs->error = bs->sr = bs->bc = 0; + bs->ptr = bs->buf = buffer_start; + bs->end = buffer_end; + bs->wrap = bs_write; +} + +// This function is only called from the putbit() and putbits() macros when +// the buffer is full, which is now flagged as an error. + +static void bs_write (Bitstream *bs) +{ + bs->ptr = bs->buf; + bs->error = 1; +} + +// This function forces a flushing write of the specified BitStream, and +// returns the total number of bytes written into the buffer. + +uint32_t bs_close_write (Bitstream *bs) +{ + uint32_t bytes_written; + + if (bs->error) + return (uint32_t) -1; + + while (bs->bc || ((bs->ptr - bs->buf) & 1)) putbit_1 (bs); + bytes_written = bs->ptr - bs->buf; + CLEAR (*bs); + return bytes_written; +} + +#endif + +/////////////////////// Endian Correction Routines //////////////////////////// + +void little_endian_to_native (void *data, char *format) +{ + uchar *cp = (uchar *) data; + int32_t temp; + + while (*format) { + switch (*format) { + case 'L': + temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); + * (int32_t *) cp = temp; + cp += 4; + break; + + case 'S': + temp = cp [0] + (cp [1] << 8); + * (short *) cp = (short) temp; + cp += 2; + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +void native_to_little_endian (void *data, char *format) +{ + uchar *cp = (uchar *) data; + int32_t temp; + + while (*format) { + switch (*format) { + case 'L': + temp = * (int32_t *) cp; + *cp++ = (uchar) temp; + *cp++ = (uchar) (temp >> 8); + *cp++ = (uchar) (temp >> 16); + *cp++ = (uchar) (temp >> 24); + break; + + case 'S': + temp = * (short *) cp; + *cp++ = (uchar) temp; + *cp++ = (uchar) (temp >> 8); + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +////////////////////////// Debug Wrapper for Malloc /////////////////////////// + +#ifdef DEBUG_ALLOC + +void *vptrs [512]; + +static void *add_ptr (void *ptr) +{ + int i; + + for (i = 0; i < 512; ++i) + if (!vptrs [i]) { + vptrs [i] = ptr; + break; + } + + if (i == 512) + error_line ("too many mallocs!"); + + return ptr; +} + +static void *del_ptr (void *ptr) +{ + int i; + + for (i = 0; i < 512; ++i) + if (vptrs [i] == ptr) { + vptrs [i] = NULL; + break; + } + + if (i == 512) + error_line ("free invalid ptr!"); + + return ptr; +} + +void *malloc_db (uint32_t size) +{ + if (size) + return add_ptr (malloc (size)); + else + return NULL; +} + +void free_db (void *ptr) +{ + if (ptr) + free (del_ptr (ptr)); +} + +void *realloc_db (void *ptr, uint32_t size) +{ + if (ptr && size) + return add_ptr (realloc (del_ptr (ptr), size)); + else if (size) + return malloc_db (size); + else + free_db (ptr); + + return NULL; +} + +int32_t dump_alloc (void) +{ + int i, j; + + for (j = i = 0; i < 512; ++i) + if (vptrs [i]) + j++; + + return j; +} + +#endif diff --git a/Libraries/WavPack/Files/compile b/Libraries/WavPack/Files/compile new file mode 100755 index 000000000..ad57e2f68 --- /dev/null +++ b/Libraries/WavPack/Files/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-02-03.08 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/Libraries/WavPack/Files/configure.ac b/Libraries/WavPack/Files/configure.ac new file mode 100644 index 000000000..441c9b2bd --- /dev/null +++ b/Libraries/WavPack/Files/configure.ac @@ -0,0 +1,62 @@ +# wavpack 4.2 configure.ac + +AC_INIT(wavpack, 4.2, bryant@wavpack.com) +AM_INIT_AUTOMAKE(wavpack, 4.2, bryant@wavpack.com) +AC_CONFIG_SRCDIR([pack.c]) + +# Check for os version +VERSION_OS=$(uname -s) +AC_DEFINE_UNQUOTED(VERSION_OS, "$VERSION_OS", [os version]) + +# Check for processor characteristics +AC_C_BIGENDIAN(AC_DEFINE([HIGHFIRST], [1], [big-endian machine])) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL + +# Checks for libraries. +AC_CHECK_LIB(m, log10, [], AC_MSG_ERROR(math library not found)) + +# Check for iconv +AC_ARG_WITH(iconv, [ --with-iconv[=DIR] Add ICONV support (on)]) +if test "$with_iconv" = "no" ; then + AC_MSG_ERROR([[Sorry, you can't deactivate iconv.]]) +else + if test "$with_iconv" != "yes" -a "$with_iconv" != "" ; then + CPPFLAGS="${CPPFLAGS} -I$with_iconv/include" + ICONV_LIBS="-L$with_iconv/lib" + fi + + AC_CHECK_HEADER(iconv.h, + AC_MSG_CHECKING(for iconv) + AC_TRY_LINK([#include +#include ],[ +iconv_t cd = iconv_open ("",""); +iconv (cd, NULL, NULL, NULL, NULL);],[ + AC_MSG_RESULT(yes) + WITH_ICONV=1 + ICONV=""],[ + AC_MSG_RESULT(no) + AC_MSG_CHECKING(for iconv in -liconv) + + _ldflags="${LDFLAGS}" + _libs="${LIBS}" + LDFLAGS="${LDFLAGS} ${ICONV_LIBS}" + LIBS="${LIBS} -liconv" + + AC_TRY_LINK([#include +#include ],[ +iconv_t cd = iconv_open ("",""); +iconv (cd, NULL, NULL, NULL, NULL);],[ + AC_MSG_RESULT(yes) + WITH_ICONV=1 + ICONV_LIBS="${ICONV_LIBS} -liconv" + ICONV="${ICONV_LIBS}"],[ + AC_MSG_ERROR([[Can't find iconv libraries.]])])]), + AC_MSG_ERROR([[Can't find iconv headers.]])) +fi +AC_SUBST(ICONV) +AC_SUBST(ICONV_LIBS) + +AC_OUTPUT(Makefile wavpack.pc) diff --git a/Libraries/WavPack/Files/depcomp b/Libraries/WavPack/Files/depcomp new file mode 100755 index 000000000..ffcd540c3 --- /dev/null +++ b/Libraries/WavPack/Files/depcomp @@ -0,0 +1,529 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-02-09.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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 General Public License for more details. + +# You should have received a copy of the GNU 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/Libraries/WavPack/Files/extra1.c b/Libraries/WavPack/Files/extra1.c new file mode 100644 index 000000000..9c7064069 --- /dev/null +++ b/Libraries/WavPack/Files/extra1.c @@ -0,0 +1,563 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// extra1.c + +// This module handles the "extra" mode for mono files. + +#include "wavpack.h" + +#include +#include +#include +#include + +// #define EXTRA_DUMP + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +//////////////////////////////// local tables /////////////////////////////// + +extern const char default_terms [], high_terms [], fast_terms []; + +// #define MINMAX_WEIGHTS + +#ifdef MINMAX_WEIGHTS +static int32_t min_weight, max_weight; +static int min_term, max_term; +#endif + +static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_t num_samples, struct decorr_pass *dpp, int dir) +{ + int m = 0; + + dpp->sum_A = 0; + +#ifdef MINMAX_WEIGHTS + dpp->min = dpp->max = 0; +#endif + + if (dir < 0) { + out_samples += (num_samples - 1); + in_samples += (num_samples - 1); + dir = -1; + } + else + dir = 1; + + if (dpp->term > MAX_TERM) { + while (num_samples--) { + int32_t left, sam_A; + + if (dpp->term & 1) + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = left = in_samples [0]; + + left -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; +#endif + out_samples [0] = left; + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term > 0) { + while (num_samples--) { + int k = (m + dpp->term) & (MAX_TERM - 1); + int32_t left, sam_A; + + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = left = in_samples [0]; + m = (m + 1) & (MAX_TERM - 1); + + left -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; +#endif + out_samples [0] = left; + in_samples += dir; + out_samples += dir; + } + } + +#ifdef MINMAX_WEIGHTS + if (dpp->term != 0) { + if (dpp->max > max_weight) { max_weight = dpp->max; max_term = dpp->term; } + if (dpp->min < min_weight) { min_weight = dpp->min; min_term = dpp->term; } + } +#endif + + if (m && dpp->term > 0 && dpp->term <= MAX_TERM) { + int32_t temp_A [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } +} + +static void reverse_mono_decorr (struct decorr_pass *dpp) +{ + if (dpp->term > MAX_TERM) { + int32_t sam_A; + + if (dpp->term & 1) + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = sam_A; + + if (dpp->term & 1) + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = sam_A; + } + else if (dpp->term > 1) { + int i = 0, j = dpp->term - 1, cnt = dpp->term / 2; + + while (cnt--) { + i &= (MAX_TERM - 1); + j &= (MAX_TERM - 1); + dpp->samples_A [i] ^= dpp->samples_A [j]; + dpp->samples_A [j] ^= dpp->samples_A [i]; + dpp->samples_A [i++] ^= dpp->samples_A [j--]; + } + + CLEAR (dpp->samples_A); + } +} + +static void decorr_mono_buffer (int32_t *samples, int32_t *outsamples, uint32_t num_samples, struct decorr_pass *dpp) +{ + int delta = dpp->delta, pre_delta, term = dpp->term; + struct decorr_pass dp; + + if (delta == 7) + pre_delta = 7; + else if (delta < 2) + pre_delta = 3; + else + pre_delta = delta + 1; + + CLEAR (dp); + dp.term = term; + dp.delta = pre_delta; + decorr_mono_pass (samples, outsamples, num_samples > 2048 ? 2048 : num_samples, &dp, -1); + dp.delta = delta; + reverse_mono_decorr (&dp); + memcpy (dpp->samples_A, dp.samples_A, sizeof (dp.samples_A)); + dpp->weight_A = dp.weight_A; + + if (delta == 0) { + dp.delta = 1; + decorr_mono_pass (samples, outsamples, num_samples, &dp, 1); + dp.delta = 0; + memcpy (dp.samples_A, dpp->samples_A, sizeof (dp.samples_A)); + dpp->weight_A = dp.weight_A = dp.sum_A / num_samples; + } + +// if (memcmp (dpp, &dp, sizeof (dp))) +// error_line ("decorr_passes don't match, delta = %d", delta); + + decorr_mono_pass (samples, outsamples, num_samples, &dp, 1); +} + +static void recurse_mono (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], + int depth, int nterms, int delta, uint32_t input_bits, uint32_t *best_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int term, branches = ((wpc->config.extra_flags & EXTRA_BRANCHES) >> 6) - depth; + int32_t *samples, *outsamples; + uint32_t term_bits [22], bits; + + if (branches < 1 || depth + 1 == nterms) + branches = 1; + + CLEAR (term_bits); + samples = sampleptrs [depth]; + outsamples = sampleptrs [depth + 1]; + + for (term = 1; term <= 18; ++term) { + if (term == 17 && branches == 1 && depth + 1 < nterms) + continue; + + if (term >= 9 && term <= 16) + if (term > MAX_TERM || !(wpc->config.flags & CONFIG_HIGH_FLAG) || (wpc->config.extra_flags & EXTRA_SKIP_8TO16)) + continue; + + if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term >= 5 && term <= 16)) + continue; + + dps [depth].term = term; + dps [depth].delta = delta; + decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); + bits = log2buffer (outsamples, wps->wphdr.block_samples); + + if (bits < *best_bits) { + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * (depth + 1)); + memcpy (sampleptrs [nterms + 1], sampleptrs [depth + 1], wps->wphdr.block_samples * 4); + } + + term_bits [term + 3] = bits; + } + + while (depth + 1 < nterms && branches--) { + uint32_t local_best_bits = input_bits; + int best_term = 0, i; + + for (i = 0; i < 22; ++i) + if (term_bits [i] && term_bits [i] < local_best_bits) { + local_best_bits = term_bits [i]; + term_bits [i] = 0; + best_term = i - 3; + } + + if (!best_term) + break; + + dps [depth].term = best_term; + dps [depth].delta = delta; + decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); + +// if (log2buffer (outsamples, wps->wphdr.block_samples * 2) != local_best_bits) +// error_line ("data doesn't match!"); + + recurse_mono (wpc, sampleptrs, dps, depth + 1, nterms, delta, local_best_bits, best_bits); + } +} + +static void delta_mono (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], + int nterms, uint32_t *best_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int lower = FALSE, delta, d; + uint32_t bits; + + if (wps->decorr_passes [0].term) + delta = wps->decorr_passes [0].delta; + else + return; + + for (d = delta - 1; d >= 0; --d) { + int i; + + if (!d && (wps->wphdr.flags & HYBRID_FLAG)) + break; + + for (i = 0; i < nterms && wps->decorr_passes [i].term; ++i) { + dps [i].term = wps->decorr_passes [i].term; + dps [i].delta = d; + decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + } + + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); + + if (bits < *best_bits) { + lower = TRUE; + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); + } + else + break; + } + + for (d = delta + 1; !lower && d <= 7; ++d) { + int i; + + for (i = 0; i < nterms && wps->decorr_passes [i].term; ++i) { + dps [i].term = wps->decorr_passes [i].term; + dps [i].delta = d; + decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + } + + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); + + if (bits < *best_bits) { + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); + } + else + break; + } +} + +static void sort_mono (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], + int nterms, uint32_t *best_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int reversed = TRUE; + uint32_t bits; + + while (reversed) { + int ri, i; + + memcpy (dps, wps->decorr_passes, sizeof (wps->decorr_passes)); + reversed = FALSE; + + for (ri = 0; ri < nterms && wps->decorr_passes [ri].term; ++ri) { + + if (ri + 1 >= nterms || !wps->decorr_passes [ri+1].term) + break; + + if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) { + decorr_mono_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); + continue; + } + + dps [ri] = wps->decorr_passes [ri+1]; + dps [ri+1] = wps->decorr_passes [ri]; + + for (i = ri; i < nterms && wps->decorr_passes [i].term; ++i) + decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); + + if (bits < *best_bits) { + reversed = TRUE; + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); + } + else { + dps [ri] = wps->decorr_passes [ri]; + dps [ri+1] = wps->decorr_passes [ri+1]; + decorr_mono_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); + } + } + } +} + +#define EXTRA_ADVANCED (EXTRA_BRANCHES | EXTRA_SORT_FIRST | EXTRA_SORT_LAST | EXTRA_TRY_DELTAS) + +void analyze_mono (WavpackContext *wpc, int32_t *samples) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; +#ifdef EXTRA_DUMP + uint32_t bits, best_bits, default_bits, cnt; +#else + uint32_t bits, best_bits, cnt; +#endif + const char *decorr_terms = default_terms, *tp; + int32_t *sampleptrs [MAX_NTERMS+2], *lptr; + struct decorr_pass dps [MAX_NTERMS]; + int nterms, i; + + CLEAR (wps->decorr_passes); + cnt = wps->wphdr.block_samples; + lptr = samples; + + while (cnt--) + if (*lptr++) + break; + + if (cnt == (uint32_t) -1) { + scan_word (wps, samples, wps->wphdr.block_samples, -1); + wps->num_terms = 0; + return; + } + + if (wpc->config.flags & CONFIG_HIGH_FLAG) + decorr_terms = high_terms; + else if (wpc->config.flags & CONFIG_FAST_FLAG) + decorr_terms = fast_terms; + + for (nterms = 0, tp = decorr_terms; *tp; tp++) + if (*tp > 0) + ++nterms; + + if (wpc->config.extra_flags & EXTRA_TERMS) + if ((nterms += (wpc->config.extra_flags & EXTRA_TERMS) >> 10) > MAX_NTERMS) + nterms = MAX_NTERMS; + + for (i = 0; i < nterms + 2; ++i) + sampleptrs [i] = malloc (wps->wphdr.block_samples * 4); + + memcpy (sampleptrs [nterms + 1], samples, wps->wphdr.block_samples * 4); + best_bits = log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples); + memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 4); + CLEAR (dps); + + for (tp = decorr_terms, i = 0; *tp; tp++) + if (*tp > 0) { + dps [i].term = *tp; + dps [i].delta = 2; + decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + ++i; + } + +#ifdef EXTRA_DUMP + default_bits = bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); +#else + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); +#endif + + if (bits < best_bits) { + best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); + } + + if ((wps->wphdr.flags & HYBRID_FLAG) && (wpc->config.extra_flags & EXTRA_ADVANCED)) { + int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; + int32_t *rptr = sampleptrs [nterms + 1], error = 0, temp; + + scan_word (wps, rptr, wps->wphdr.block_samples, -1); + cnt = wps->wphdr.block_samples; + lptr = sampleptrs [0]; + + if (wps->wphdr.flags & HYBRID_SHAPE) { + while (cnt--) { + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + temp = -apply_weight (shaping_weight, error); + + if (new && shaping_weight < 0 && temp) { + if (temp == error) + temp = (temp < 0) ? temp + 1 : temp - 1; + + lptr [0] += (error = nosend_word (wps, rptr [0], 0) - rptr [0] + temp); + } + else + lptr [0] += (error = nosend_word (wps, rptr [0], 0) - rptr [0]) + temp; + + lptr++; + rptr++; + } + + wps->dc.shaping_acc [0] -= wps->dc.shaping_delta [0] * wps->wphdr.block_samples; + } + else + while (cnt--) { + lptr [0] += nosend_word (wps, rptr [0], 0) - rptr [0]; + lptr++; + rptr++; + } + + memcpy (dps, wps->decorr_passes, sizeof (dps)); + + for (i = 0; i < nterms && dps [i].term; ++i) + decorr_mono_buffer (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i); + +#ifdef EXTRA_DUMP + best_bits = default_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); +#else + best_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); +#endif + + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); + } + + if (wpc->config.extra_flags & EXTRA_BRANCHES) + recurse_mono (wpc, sampleptrs, dps, 0, nterms, (int) floor (wps->delta_decay + 0.5), + log2buffer (sampleptrs [0], wps->wphdr.block_samples), &best_bits); + + if (wpc->config.extra_flags & EXTRA_SORT_FIRST) + sort_mono (wpc, sampleptrs, dps, nterms, &best_bits); + + if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) { + delta_mono (wpc, sampleptrs, dps, nterms, &best_bits); + + if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term) + wps->delta_decay = (wps->delta_decay * 2.0 + wps->decorr_passes [0].delta) / 3.0; + else + wps->delta_decay = 2.0; + } + + if (wpc->config.extra_flags & EXTRA_SORT_LAST) + sort_mono (wpc, sampleptrs, dps, nterms, &best_bits); + +#if 0 + memcpy (dps, wps->decorr_passes, sizeof (dps)); + + for (i = 0; i < nterms && dps [i].term; ++i) + decorr_mono_pass (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i, 1); + + if (log2buffer (sampleptrs [i], wps->wphdr.block_samples) != best_bits) + error_line ("(1) samples do not match!"); + + if (log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples) != best_bits) + error_line ("(2) samples do not match!"); +#endif + + scan_word (wps, sampleptrs [nterms + 1], wps->wphdr.block_samples, -1); + +#ifdef EXTRA_DUMP + if (wpc->config.extra_flags & EXTRA_DUMP_TERMS) { + char string [256], substring [20]; + int i; + + sprintf (string, "M: delta = %.4f%%, terms =", + ((double) best_bits - default_bits) / 256.0 / wps->wphdr.block_samples / 32.0 * 100.0); + + for (i = 0; i < nterms; ++i) { + if (wps->decorr_passes [i].term) { + if (i && wps->decorr_passes [i-1].delta == wps->decorr_passes [i].delta) + sprintf (substring, " %d", wps->decorr_passes [i].term); + else + sprintf (substring, " %d->%d", wps->decorr_passes [i].term, + wps->decorr_passes [i].delta); + } + else + sprintf (substring, " *"); + + strcat (string, substring); + } + + error_line (string); + } +#endif + + for (i = 0; i < nterms; ++i) + if (!wps->decorr_passes [i].term) + break; + + wps->num_terms = i; + + for (i = 0; i < nterms + 2; ++i) + free (sampleptrs [i]); + +#ifdef MINMAX_WEIGHTS + error_line ("weight range = %ld (%d) to %ld (%d)", min_weight, min_term, max_weight, max_term); +#endif +} diff --git a/Libraries/WavPack/Files/extra2.c b/Libraries/WavPack/Files/extra2.c new file mode 100644 index 000000000..777abe3be --- /dev/null +++ b/Libraries/WavPack/Files/extra2.c @@ -0,0 +1,792 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// extra2.c + +// This module handles the "extra" mode for stereo files. + +#include "wavpack.h" + +#include +#include +#include +#include + +// #define EXTRA_DUMP + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +extern const char default_terms [], high_terms [], fast_terms []; + +// #define MINMAX_WEIGHTS + +#ifdef MINMAX_WEIGHTS +static int32_t min_weight, max_weight; +static int min_term, max_term; +#endif + +static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) +{ + int m = 0; + + dpp->sum_A = dpp->sum_B = 0; + +#ifdef MINMAX_WEIGHTS + dpp->min = dpp->max = 0; +#endif + + if (dir < 0) { + out_samples += (num_samples - 1) * 2; + in_samples += (num_samples - 1) * 2; + dir = -2; + } + else + dir = 2; + + if (dpp->term == 17) { + while (num_samples--) { + int32_t left, right; + int32_t sam_A, sam_B; + + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = left = in_samples [0]; + left -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; + out_samples [0] = left; + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = right = in_samples [1]; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_B += dpp->weight_B; + out_samples [1] = right; + +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; + if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; +#endif + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == 18) { + while (num_samples--) { + int32_t left, right; + int32_t sam_A, sam_B; + + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = left = in_samples [0]; + left -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; + out_samples [0] = left; + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = right = in_samples [1]; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_B += dpp->weight_B; + out_samples [1] = right; + +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; + if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; +#endif + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term > 0) { + while (num_samples--) { + int k = (m + dpp->term) & (MAX_TERM - 1); + int32_t left, right; + int32_t sam_A, sam_B; + + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = left = in_samples [0]; + left -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; + out_samples [0] = left; + + sam_B = dpp->samples_B [m]; + dpp->samples_B [k] = right = in_samples [1]; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_B += dpp->weight_B; + out_samples [1] = right; + +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; + if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; +#endif + in_samples += dir; + out_samples += dir; + m = (m + 1) & (MAX_TERM - 1); + } + } + else if (dpp->term == -1) { + while (num_samples--) { + int32_t left = in_samples [0]; + int32_t right = in_samples [1]; + int32_t sam_A = dpp->samples_A [0], sam_B = left; + + dpp->samples_A [0] = right; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + left -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; + dpp->sum_B += dpp->weight_B; +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; + if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; +#endif + out_samples [0] = left; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == -2) { + while (num_samples--) { + int32_t left = in_samples [0]; + int32_t right = in_samples [1]; + int32_t sam_B = dpp->samples_B [0], sam_A = right; + + dpp->samples_B [0] = left; + left -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_A += dpp->weight_A; + dpp->sum_B += dpp->weight_B; +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; + if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; +#endif + out_samples [0] = left; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == -3) { + while (num_samples--) { + int32_t left = in_samples [0]; + int32_t right = in_samples [1]; + int32_t sam_A = dpp->samples_A [0], sam_B = dpp->samples_B [0]; + + dpp->samples_A [0] = right; + dpp->samples_B [0] = left; + left -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_A += dpp->weight_A; + dpp->sum_B += dpp->weight_B; +#ifdef MINMAX_WEIGHTS + if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; + if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; + if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; + if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; +#endif + out_samples [0] = left; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + } + } + +#ifdef MINMAX_WEIGHTS + if (dpp->term != 0) { + if (dpp->max > max_weight) { max_weight = dpp->max; max_term = dpp->term; } + if (dpp->min < min_weight) { min_weight = dpp->min; min_term = dpp->term; } + } +#endif + + if (m && dpp->term > 0 && dpp->term <= MAX_TERM) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } +} + +static void reverse_decorr (struct decorr_pass *dpp) +{ + if (dpp->term > MAX_TERM) { + int32_t sam_A, sam_B; + + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_A [0] = sam_A; + dpp->samples_B [0] = sam_B; + + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + dpp->samples_A [1] = sam_A; + dpp->samples_B [1] = sam_B; + } + else if (dpp->term > 1) { + int i = 0, j = dpp->term - 1, cnt = dpp->term / 2; + + while (cnt--) { + i &= (MAX_TERM - 1); + j &= (MAX_TERM - 1); + dpp->samples_A [i] ^= dpp->samples_A [j]; + dpp->samples_A [j] ^= dpp->samples_A [i]; + dpp->samples_A [i] ^= dpp->samples_A [j]; + dpp->samples_B [i] ^= dpp->samples_B [j]; + dpp->samples_B [j] ^= dpp->samples_B [i]; + dpp->samples_B [i++] ^= dpp->samples_B [j--]; + } + +// CLEAR (dpp->samples_A); +// CLEAR (dpp->samples_B); + } + else if (dpp->term == -1) { + } + else if (dpp->term == -2) { + } + else if (dpp->term == -3) { + } +} + +static void decorr_stereo_buffer (int32_t *samples, int32_t *outsamples, int32_t num_samples, struct decorr_pass *dpp) +{ + int delta = dpp->delta, pre_delta; + int term = dpp->term; + struct decorr_pass dp; + + if (delta == 7) + pre_delta = 7; + else if (delta < 2) + pre_delta = 3; + else + pre_delta = delta + 1; + + CLEAR (dp); + dp.term = term; + dp.delta = pre_delta; + decorr_stereo_pass (samples, outsamples, num_samples > 2048 ? 2048 : num_samples, &dp, -1); + dp.delta = delta; + reverse_decorr (&dp); + memcpy (dpp->samples_A, dp.samples_A, sizeof (dp.samples_A)); + memcpy (dpp->samples_B, dp.samples_B, sizeof (dp.samples_B)); + dpp->weight_A = dp.weight_A; + dpp->weight_B = dp.weight_B; + + if (delta == 0) { + dp.delta = 1; + decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1); + dp.delta = 0; + memcpy (dp.samples_A, dpp->samples_A, sizeof (dp.samples_A)); + memcpy (dp.samples_B, dpp->samples_B, sizeof (dp.samples_B)); + dpp->weight_A = dp.weight_A = dp.sum_A / num_samples; + dpp->weight_B = dp.weight_B = dp.sum_B / num_samples; + } + +// if (memcmp (dpp, &dp, sizeof (dp))) +// error_line ("decorr_passes don't match, delta = %d", delta); + + decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1); +} + +static void recurse_stereo (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], + int depth, int nterms, int delta, uint32_t input_bits, uint32_t *best_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int term, branches = ((wpc->config.extra_flags & EXTRA_BRANCHES) >> 6) - depth; + int32_t *samples, *outsamples; + uint32_t term_bits [22], bits; + + if (branches < 1 || depth + 1 == nterms) + branches = 1; + + CLEAR (term_bits); + samples = sampleptrs [depth]; + outsamples = sampleptrs [depth + 1]; + + for (term = -3; term <= 18; ++term) { + if (!term) + continue; + + if (term == 17 && branches == 1 && depth + 1 < nterms) + continue; + + if (term == -1 || term == -2) + if (!(wps->wphdr.flags & CROSS_DECORR)) + continue; + + if (term >= 9 && term <= 16) + if (term > MAX_TERM || !(wpc->config.flags & CONFIG_HIGH_FLAG) || (wpc->config.extra_flags & EXTRA_SKIP_8TO16)) + continue; + + if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term >= 5 && term <= 16)) + continue; + + dps [depth].term = term; + dps [depth].delta = delta; + decorr_stereo_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); + bits = log2buffer (outsamples, wps->wphdr.block_samples * 2); + + if (bits < *best_bits) { + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * (depth + 1)); + memcpy (sampleptrs [nterms + 1], sampleptrs [depth + 1], wps->wphdr.block_samples * 8); + } + + term_bits [term + 3] = bits; + } + + while (depth + 1 < nterms && branches--) { + uint32_t local_best_bits = input_bits; + int best_term = 0, i; + + for (i = 0; i < 22; ++i) + if (term_bits [i] && term_bits [i] < local_best_bits) { + local_best_bits = term_bits [i]; + term_bits [i] = 0; + best_term = i - 3; + } + + if (!best_term) + break; + + dps [depth].term = best_term; + dps [depth].delta = delta; + decorr_stereo_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); + +// if (log2buffer (outsamples, wps->wphdr.block_samples * 2) != local_best_bits) +// error_line ("data doesn't match!"); + + recurse_stereo (wpc, sampleptrs, dps, depth + 1, nterms, delta, local_best_bits, best_bits); + } +} + +static void delta_stereo (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], + int nterms, uint32_t *best_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int lower = FALSE; + int delta, d; + uint32_t bits; + + if (wps->decorr_passes [0].term) + delta = wps->decorr_passes [0].delta; + else + return; + + for (d = delta - 1; d >= 0; --d) { + int i; + + if (!d && (wps->wphdr.flags & HYBRID_FLAG)) + break; + + for (i = 0; i < nterms && wps->decorr_passes [i].term; ++i) { + dps [i].term = wps->decorr_passes [i].term; + dps [i].delta = d; + decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + } + + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); + + if (bits < *best_bits) { + lower = TRUE; + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); + } + else + break; + } + + for (d = delta + 1; !lower && d <= 7; ++d) { + int i; + + for (i = 0; i < nterms && wps->decorr_passes [i].term; ++i) { + dps [i].term = wps->decorr_passes [i].term; + dps [i].delta = d; + decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + } + + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); + + if (bits < *best_bits) { + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); + } + else + break; + } +} + +static void sort_stereo (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], + int nterms, uint32_t *best_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int reversed = TRUE; + uint32_t bits; + + while (reversed) { + int ri, i; + + memcpy (dps, wps->decorr_passes, sizeof (wps->decorr_passes)); + reversed = FALSE; + + for (ri = 0; ri < nterms && wps->decorr_passes [ri].term; ++ri) { + + if (ri + 1 >= nterms || !wps->decorr_passes [ri+1].term) + break; + + if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) { + decorr_stereo_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); + continue; + } + + dps [ri] = wps->decorr_passes [ri+1]; + dps [ri+1] = wps->decorr_passes [ri]; + + for (i = ri; i < nterms && wps->decorr_passes [i].term; ++i) + decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); + + if (bits < *best_bits) { + reversed = TRUE; + *best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); + } + else { + dps [ri] = wps->decorr_passes [ri]; + dps [ri+1] = wps->decorr_passes [ri+1]; + decorr_stereo_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); + } + } + } +} + +#define EXTRA_ADVANCED (EXTRA_BRANCHES | EXTRA_SORT_FIRST | EXTRA_SORT_LAST | EXTRA_TRY_DELTAS) + +void analyze_stereo (WavpackContext *wpc, int32_t *samples) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; +#ifdef EXTRA_DUMP + uint32_t bits, best_bits, default_bits, cnt; +#else + uint32_t bits, best_bits, cnt; +#endif + const char *decorr_terms = default_terms, *tp; + int32_t *sampleptrs [MAX_NTERMS+2], *lptr; + struct decorr_pass dps [MAX_NTERMS]; + int nterms, i; + + + CLEAR (wps->decorr_passes); + cnt = wps->wphdr.block_samples * 2; + lptr = samples; + + while (cnt--) + if (*lptr++) + break; + + if (cnt == (uint32_t) -1) { + scan_word (wps, samples, wps->wphdr.block_samples, -1); + wps->num_terms = 0; + return; + } + + if (wpc->config.flags & CONFIG_HIGH_FLAG) + decorr_terms = high_terms; + else if (wpc->config.flags & CONFIG_FAST_FLAG) + decorr_terms = fast_terms; + + nterms = strlen (decorr_terms); + + if (wpc->config.extra_flags & EXTRA_TERMS) + if ((nterms += (wpc->config.extra_flags & EXTRA_TERMS) >> 10) > MAX_NTERMS) + nterms = MAX_NTERMS; + + for (i = 0; i < nterms + 2; ++i) + sampleptrs [i] = malloc (wps->wphdr.block_samples * 8); + + memcpy (sampleptrs [nterms + 1], samples, wps->wphdr.block_samples * 8); + best_bits = log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples * 2); + + if ((wpc->config.extra_flags & EXTRA_STEREO_MODES) || !(wps->wphdr.flags & JOINT_STEREO)) { + memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 8); + + CLEAR (dps); + + for (tp = decorr_terms, i = 0; *tp;) { + if (*tp > 0 || (wps->wphdr.flags & CROSS_DECORR)) + dps [i].term = *tp++; + else { + dps [i].term = -3; + tp++; + } + + dps [i].delta = 2; + decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + ++i; + } + +#ifdef EXTRA_DUMP + default_bits = bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); +#else + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); +#endif + + wps->wphdr.flags &= ~JOINT_STEREO; + + if (bits < best_bits) { + best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); + } + } + + if ((wpc->config.extra_flags & EXTRA_STEREO_MODES) || (wps->wphdr.flags & JOINT_STEREO)) { + memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 8); + cnt = wps->wphdr.block_samples; + lptr = sampleptrs [0]; + + while (cnt--) { + lptr [1] += ((lptr [0] -= lptr [1]) >> 1); + lptr += 2; + } + + CLEAR (dps); + + for (tp = decorr_terms, i = 0; *tp;) { + if (*tp > 0 || (wps->wphdr.flags & CROSS_DECORR)) + dps [i].term = *tp++; + else { + dps [i].term = -3; + tp++; + } + + dps [i].delta = 2; + decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); + ++i; + } + +#ifdef EXTRA_DUMP + default_bits = bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); +#else + bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); +#endif + + wps->wphdr.flags |= JOINT_STEREO; + + if (bits < best_bits) { + best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); + } + else { + memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 8); + wps->wphdr.flags &= ~JOINT_STEREO; + } + } + + if ((wps->wphdr.flags & HYBRID_FLAG) && (wpc->config.extra_flags & EXTRA_ADVANCED)) { + int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; + int32_t *rptr = sampleptrs [nterms + 1], error [2], temp; + + scan_word (wps, rptr, wps->wphdr.block_samples, -1); + cnt = wps->wphdr.block_samples; + lptr = sampleptrs [0]; + CLEAR (error); + + if (wps->wphdr.flags & HYBRID_SHAPE) { + while (cnt--) { + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + temp = -apply_weight (shaping_weight, error [0]); + + if (new && shaping_weight < 0 && temp) { + if (temp == error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + lptr [0] += (error [0] = nosend_word (wps, rptr [0], 0) - rptr [0] + temp); + } + else + lptr [0] += (error [0] = nosend_word (wps, rptr [0], 0) - rptr [0]) + temp; + + shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16; + temp = -apply_weight (shaping_weight, error [1]); + + if (new && shaping_weight < 0 && temp) { + if (temp == error [1]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + lptr [1] += (error [1] = nosend_word (wps, rptr [1], 1) - rptr [1] + temp); + } + else + lptr [1] += (error [1] = nosend_word (wps, rptr [1], 1) - rptr [1]) + temp; + + lptr += 2; + rptr += 2; + } + + wps->dc.shaping_acc [0] -= wps->dc.shaping_delta [0] * wps->wphdr.block_samples; + wps->dc.shaping_acc [1] -= wps->dc.shaping_delta [1] * wps->wphdr.block_samples; + } + else + while (cnt--) { + lptr [0] += nosend_word (wps, rptr [0], 0) - rptr [0]; + lptr [1] += nosend_word (wps, rptr [1], 1) - rptr [1]; + lptr += 2; + rptr += 2; + } + + memcpy (dps, wps->decorr_passes, sizeof (dps)); + + for (i = 0; i < nterms && dps [i].term; ++i) + decorr_stereo_buffer (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i); + +#ifdef EXTRA_DUMP + best_bits = default_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); +#else + best_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); +#endif + + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); + memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); + } + + if (wpc->config.extra_flags & EXTRA_BRANCHES) + recurse_stereo (wpc, sampleptrs, dps, 0, nterms, (int) floor (wps->delta_decay + 0.5), + log2buffer (sampleptrs [0], wps->wphdr.block_samples * 2), &best_bits); + + if (wpc->config.extra_flags & EXTRA_SORT_FIRST) + sort_stereo (wpc, sampleptrs, dps, nterms, &best_bits); + + if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) { + delta_stereo (wpc, sampleptrs, dps, nterms, &best_bits); + + if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term) + wps->delta_decay = (wps->delta_decay * 2.0 + wps->decorr_passes [0].delta) / 3.0; + else + wps->delta_decay = 2.0; + } + + if (wpc->config.extra_flags & EXTRA_SORT_LAST) + sort_stereo (wpc, sampleptrs, dps, nterms, &best_bits); + +#if 0 + memcpy (dps, wps->decorr_passes, sizeof (dps)); + + for (i = 0; i < nterms && dps [i].term; ++i) + decorr_stereo_pass (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i, 1); + + if (log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2) != best_bits) + error_line ("(1) samples do not match!"); + + if (log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples * 2) != best_bits) + error_line ("(2) samples do not match!"); +#endif + + scan_word (wps, sampleptrs [nterms + 1], wps->wphdr.block_samples, -1); + +#ifdef EXTRA_DUMP + if (1) { + char string [256], substring [20]; + int i; + + sprintf (string, "%s: delta = %.4f%%, terms =", + (wps->wphdr.flags & JOINT_STEREO) ? "JS" : "TS", + ((double) best_bits - default_bits) / 256.0 / wps->wphdr.block_samples / 32.0 * 100.0); + + for (i = 0; i < nterms; ++i) { + if (wps->decorr_passes [i].term) { + if (i && wps->decorr_passes [i-1].delta == wps->decorr_passes [i].delta) + sprintf (substring, " %d", wps->decorr_passes [i].term); + else + sprintf (substring, " %d->%d", wps->decorr_passes [i].term, + wps->decorr_passes [i].delta); + } + else + sprintf (substring, " *"); + + strcat (string, substring); + } + + error_line (string); + } +#endif + + for (i = 0; i < nterms; ++i) + if (!wps->decorr_passes [i].term) + break; + + wps->num_terms = i; + + for (i = 0; i < nterms + 2; ++i) + free (sampleptrs [i]); + +#ifdef MINMAX_WEIGHTS + error_line ("weight range = %ld (%d) to %ld (%d)", min_weight, min_term, max_weight, max_term); +#endif +} diff --git a/Libraries/WavPack/Files/float.c b/Libraries/WavPack/Files/float.c new file mode 100644 index 000000000..19fb3a460 --- /dev/null +++ b/Libraries/WavPack/Files/float.c @@ -0,0 +1,371 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// float.c + +#include "wavpack.h" + +#include + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +#ifdef PACK + +void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_FLOAT_INFO; + *byteptr++ = wps->float_flags; + *byteptr++ = wps->float_shift; + *byteptr++ = wps->float_max_exp; + *byteptr++ = wps->float_norm_exp; + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values) +{ + int32_t shifted_ones = 0, shifted_zeros = 0, shifted_both = 0; + int32_t false_zeros = 0, neg_zeros = 0; + uint32_t ordata = 0, crc = 0xffffffff; + int max_exp = 0, shift_count; + int32_t count, value; + f32 *dp; + + wps->float_shift = wps->float_flags = 0; + + for (dp = values, count = num_values; count--; dp++) { + crc = crc * 27 + dp->mantissa * 9 + dp->exponent * 3 + dp->sign; + + if (dp->exponent > max_exp && dp->exponent < 255) + max_exp = dp->exponent; + } + + wps->crc_x = crc; + + for (dp = values, count = num_values; count--; dp++) { + if (dp->exponent == 255) { + wps->float_flags |= FLOAT_EXCEPTIONS; + value = 0x1000000; + shift_count = 0; + } + else if (dp->exponent) { + shift_count = max_exp - dp->exponent; + value = 0x800000 + dp->mantissa; + } + else { + shift_count = max_exp ? max_exp - 1 : 0; + value = dp->mantissa; + +// if (dp->mantissa) +// denormals++; + } + + if (shift_count < 25) + value >>= shift_count; + else + value = 0; + + if (!value) { + if (dp->exponent || dp->mantissa) + ++false_zeros; + else if (dp->sign) + ++neg_zeros; + } + else if (shift_count) { + int32_t mask = (1 << shift_count) - 1; + + if (!(dp->mantissa & mask)) + shifted_zeros++; + else if ((dp->mantissa & mask) == mask) + shifted_ones++; + else + shifted_both++; + } + + ordata |= value; + * (int32_t *) dp = (dp->sign) ? -value : value; + } + + wps->float_max_exp = max_exp; + + if (shifted_both) + wps->float_flags |= FLOAT_SHIFT_SENT; + else if (shifted_ones && !shifted_zeros) + wps->float_flags |= FLOAT_SHIFT_ONES; + else if (shifted_ones && shifted_zeros) + wps->float_flags |= FLOAT_SHIFT_SAME; + else if (ordata && !(ordata & 1)) { + while (!(ordata & 1)) { + wps->float_shift++; + ordata >>= 1; + } + + for (dp = values, count = num_values; count--; dp++) + * (int32_t *) dp >>= wps->float_shift; + } + + wps->wphdr.flags &= ~MAG_MASK; + + while (ordata) { + wps->wphdr.flags += 1 << MAG_LSB; + ordata >>= 1; + } + + if (false_zeros || neg_zeros) + wps->float_flags |= FLOAT_ZEROS_SENT; + + if (neg_zeros) + wps->float_flags |= FLOAT_NEG_ZEROS; + +// error_line ("samples = %d, max exp = %d, pre-shift = %d, denormals = %d", +// num_values, max_exp, wps->float_shift, denormals); +// if (wps->float_flags & FLOAT_EXCEPTIONS) +// error_line ("exceptions!"); +// error_line ("shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d", +// shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros); + + return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME); +} + +void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values) +{ + int max_exp = wps->float_max_exp; + int32_t count, value, shift_count; + f32 *dp; + + for (dp = values, count = num_values; count--; dp++) { + if (dp->exponent == 255) { + if (dp->mantissa) { + putbit_1 (&wps->wvxbits); + putbits (dp->mantissa, 23, &wps->wvxbits); + } + else { + putbit_0 (&wps->wvxbits); + } + + value = 0x1000000; + shift_count = 0; + } + else if (dp->exponent) { + shift_count = max_exp - dp->exponent; + value = 0x800000 + dp->mantissa; + } + else { + shift_count = max_exp ? max_exp - 1 : 0; + value = dp->mantissa; + } + + if (shift_count < 25) + value >>= shift_count; + else + value = 0; + + if (!value) { + if (wps->float_flags & FLOAT_ZEROS_SENT) { + if (dp->exponent || dp->mantissa) { + putbit_1 (&wps->wvxbits); + putbits (dp->mantissa, 23, &wps->wvxbits); + + if (max_exp >= 25) { + putbits (dp->exponent, 8, &wps->wvxbits); + } + + putbit (dp->sign, &wps->wvxbits); + } + else { + putbit_0 (&wps->wvxbits); + + if (wps->float_flags & FLOAT_NEG_ZEROS) + putbit (dp->sign, &wps->wvxbits); + } + } + } + else if (shift_count) { + if (wps->float_flags & FLOAT_SHIFT_SENT) { + int32_t data = dp->mantissa & ((1 << shift_count) - 1); + putbits (data, shift_count, &wps->wvxbits); + } + else if (wps->float_flags & FLOAT_SHIFT_SAME) { + putbit (dp->mantissa & 1, &wps->wvxbits); + } + } + } +} + +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + char *byteptr = wpmd->data; + + if (bytecnt != 4) + return FALSE; + + wps->float_flags = *byteptr++; + wps->float_shift = *byteptr++; + wps->float_max_exp = *byteptr++; + wps->float_norm_exp = *byteptr; + return TRUE; +} + +#endif + +#ifdef UNPACK + +static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values); + +void float_values (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + uint32_t crc = wps->crc_x; + + if (!bs_is_open (&wps->wvxbits)) { + float_values_nowvx (wps, values, num_values); + return; + } + + while (num_values--) { + int shift_count = 0, exp = wps->float_max_exp; + f32 outval = { 0, 0, 0 }; + uint32_t temp; + + if (*values == 0) { + if (wps->float_flags & FLOAT_ZEROS_SENT) { + if (getbit (&wps->wvxbits)) { + getbits (&temp, 23, &wps->wvxbits); + outval.mantissa = temp; + + if (exp >= 25) { + getbits (&temp, 8, &wps->wvxbits); + outval.exponent = temp; + } + + outval.sign = getbit (&wps->wvxbits); + } + else if (wps->float_flags & FLOAT_NEG_ZEROS) + outval.sign = getbit (&wps->wvxbits); + } + } + else { + *values <<= wps->float_shift; + + if (*values < 0) { + *values = -*values; + outval.sign = 1; + } + + if (*values == 0x1000000) { + if (getbit (&wps->wvxbits)) { + getbits (&temp, 23, &wps->wvxbits); + outval.mantissa = temp; + } + + outval.exponent = 255; + } + else { + if (exp) + while (!(*values & 0x800000) && --exp) { + shift_count++; + *values <<= 1; + } + + if (shift_count) { + if ((wps->float_flags & FLOAT_SHIFT_ONES) || + ((wps->float_flags & FLOAT_SHIFT_SAME) && getbit (&wps->wvxbits))) + *values |= ((1 << shift_count) - 1); + else if (wps->float_flags & FLOAT_SHIFT_SENT) { + getbits (&temp, shift_count, &wps->wvxbits); + *values |= temp & ((1 << shift_count) - 1); + } + } + + outval.mantissa = *values; + outval.exponent = exp; + } + } + + crc = crc * 27 + outval.mantissa * 9 + outval.exponent * 3 + outval.sign; + * (f32 *) values++ = outval; + } + + wps->crc_x = crc; +} + +static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + while (num_values--) { + int shift_count = 0, exp = wps->float_max_exp; + f32 outval = { 0, 0, 0 }; + + if (*values) { + *values <<= wps->float_shift; + + if (*values < 0) { + *values = -*values; + outval.sign = 1; + } + + if (*values >= 0x1000000) { + while (*values & 0xf000000) { + *values >>= 1; + ++exp; + } + } + else if (exp) { + while (!(*values & 0x800000) && --exp) { + shift_count++; + *values <<= 1; + } + + if (shift_count && (wps->float_flags & FLOAT_SHIFT_ONES)) + *values |= ((1 << shift_count) - 1); + } + + outval.mantissa = *values; + outval.exponent = exp; + } + + * (f32 *) values++ = outval; + } +} + +void float_normalize (int32_t *values, int32_t num_values, int delta_exp) +{ + f32 *fvalues = (f32 *) values, fzero = { 0, 0, 0 }; + int exp; + + if (!delta_exp) + return; + + while (num_values--) { + if ((exp = fvalues->exponent) == 0 || exp + delta_exp <= 0) + *fvalues = fzero; + else if (exp == 255 || (exp += delta_exp) >= 255) { + fvalues->exponent = 255; + fvalues->mantissa = 0; + } + else + fvalues->exponent = exp; + + fvalues++; + } +} + +#endif diff --git a/Libraries/WavPack/Files/format.txt b/Libraries/WavPack/Files/format.txt new file mode 100644 index 000000000..8185a0b7f --- /dev/null +++ b/Libraries/WavPack/Files/format.txt @@ -0,0 +1,96 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + + WavPack 4.0 File / Block Format + ------------------------------- + +A WavPack 4.0 file consists of a series of WavPack audio blocks. It may also +contain tags and other information, but these must be outside the blocks +(either before, in-between, or after) and are ignored for the purpose of +unpacking audio data. The WavPack blocks are easy to identify by their +unique header data, and by looking in the header it is very easy to +determine the total size of the block, both in physical bytes and compressed +samples. There are no seek tables. + +The blocks (or frames, if you prefer) are completely independent in that they +can be decoded to mono or stereo audio all by themselves. A single function +is provided to convert a whole block into its corresponding audio data. +Similarly, a function is provided to convert a block of audio samples into +a finished WavPack block. These all work in memory; disk I/O is handled +outside. It is also possible to decode or encode blocks in smaller increments +if it is important to distribute CPU load more evenly over time. The blocks may +also be decoded without reading the whole block into memory, although this +would only be important for hardware decoding. + +The blocks may contain any number of samples, either stereo or mono. Obviously, +putting more samples in each block is more efficient, but they are reasonably +efficient down to even a thousand samples. I have set the max size to 1 MB for +the whole block, but this is arbitrary. The blocks may be lossless or lossy +(currently the lossy modes are basically CBR, but I am planning a quality +based VBR version also). + +For multichannel audio, the data is divided into some number of stereo and mono +streams and multiplexed into separate blocks. Because blocks are independent +there can be a mix of sampling rates, but all the streams must be sliced at +the same point in time which is a multiple of all the sampling rates. The +metadata contains source information (like front, center, rear, etc.). + +Correction files (.wvc) have an identical structure to the main file (.wv) and +there is a one-to-one correspondence between main file blocks that contain +audio and their correction file match (blocks that do not contain audio do +not exist in the correction file). The only difference in the headers of +main blocks and correction blocks is the CRC value, although it is easy to +tell the blocks apart by looking at the metadata ids. + +Here is the 32-byte header at the front of every block: + +typedef struct { + char ckID [4]; // "wvpk" + long ckSize; // size of entire frame (minus 8, of course) + short version; // 0x403 for now + uchar track_no; // track number (0 if not used, like now) + uchar index_no; // track sub-index (0 if not used, like now) + ulong total_samples; // for entire file (-1 if unknown) + ulong block_index; // index of first sample in block (to file begin) + ulong block_samples; // # samples in this block + ulong flags; // various flags for id and decoding + ulong crc; // crc for actual decoded data +} WavpackHeader; + +The "flags" field contains information for decoding the block along with some +general information including sample size and format, hybrid/lossless, +mono/stereo and sampling rate. This structure is stored "little-endian". + +Following the 32-byte header to the end of the block are a series of "metadata" +sub-blocks. These may from 2 bytes long to the size of the entire block and are +extremely easy to parse (even without knowing what they mean). Currently these +mostly contain extra information needed to decode the audio, but may also +contain user information. The only non-audio information I currently have +implemented is a copy of the original wave RIFF header (or trailer if present), +and the MD5 checksums, but there is plenty of flexibility here. For example, +these metadata blocks could store cuesheets, artist/title information, +replaygain values, even pictures or lyrics. The final metadata sub-blocks are +the actual audio bitstreams, which have ids for standard audio (wvbits), +correction data (wvcbits), and a special extension for large integer and +floating-point data (wvxbits). + +The format of the metadata is: + + uchar id; // mask meaning + // ---- ------- + // 0x1f metadata function + // 0x20 decoder need not understand metadata + // 0x40 actual data byte length is 1 less + // 0x80 large block (> 255 words) + + uchar word_size; // small block: data size in words (padded) + or... + uchar word_size [3]; // large block: data size in words (padded, + little-endian) + + ushort data [word_size]; // data, padded to an even # of bytes diff --git a/Libraries/WavPack/Files/install-sh b/Libraries/WavPack/Files/install-sh new file mode 100755 index 000000000..1a8353401 --- /dev/null +++ b/Libraries/WavPack/Files/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-02-02.21 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/Libraries/WavPack/Files/license.txt b/Libraries/WavPack/Files/license.txt new file mode 100644 index 000000000..c21b40fbb --- /dev/null +++ b/Libraries/WavPack/Files/license.txt @@ -0,0 +1,25 @@ + Copyright (c) 1998 - 2005 Conifer Software + All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Conifer Software nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Libraries/WavPack/Files/md5.c b/Libraries/WavPack/Files/md5.c new file mode 100644 index 000000000..fe27c4539 --- /dev/null +++ b/Libraries/WavPack/Files/md5.c @@ -0,0 +1,263 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* Brutally hacked by John Walker back from ANSI C to K&R (no + prototypes) to maintain the tradition that Netfone will compile + with Sun's original "cc". */ + +#include /* for memcpy() */ +#include "md5.h" + +#ifdef sgi +#define HIGHFIRST +#endif + +#ifdef sun +#define HIGHFIRST +#endif + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(buf, longs) + unsigned char *buf; unsigned longs; +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(ctx) + struct MD5Context *ctx; +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(ctx, buf, len) + struct MD5Context *ctx; unsigned char *buf; unsigned len; +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(digest, ctx) + unsigned char digest[16]; struct MD5Context *ctx; +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(buf, in) + uint32 buf[4]; uint32 in[16]; +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/Libraries/WavPack/Files/md5.h b/Libraries/WavPack/Files/md5.h new file mode 100644 index 000000000..5aa29d201 --- /dev/null +++ b/Libraries/WavPack/Files/md5.h @@ -0,0 +1,26 @@ +#ifndef MD5_H +#define MD5_H + +#if defined (__alpha__) || defined (__x86_64__) +typedef unsigned int uint32; +#else +typedef unsigned long uint32; +#endif + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +extern void MD5Init(); +extern void MD5Update(); +extern void MD5Final(); +extern void MD5Transform(); + +/* + * This is needed to make RSAREF happy on some MS-DOS compilers. + */ +typedef struct MD5Context MD5_CTX; + +#endif /* !MD5_H */ diff --git a/Libraries/WavPack/Files/metadata.c b/Libraries/WavPack/Files/metadata.c new file mode 100644 index 000000000..922c16694 --- /dev/null +++ b/Libraries/WavPack/Files/metadata.c @@ -0,0 +1,310 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// metadata.c + +// This module handles the metadata structure introduced in WavPack 4.0 + +#include "wavpack.h" + +#include +#include + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +int read_metadata_buff (WavpackMetadata *wpmd, uchar *blockbuff, uchar **buffptr) +{ + WavpackHeader *wphdr = (WavpackHeader *) blockbuff; + uchar *buffend = blockbuff + wphdr->ckSize + 8; + + if (buffend - *buffptr < 2) + return FALSE; + + wpmd->id = *(*buffptr)++; + wpmd->byte_length = *(*buffptr)++ << 1; + + if (wpmd->id & ID_LARGE) { + wpmd->id &= ~ID_LARGE; + + if (buffend - *buffptr < 2) + return FALSE; + + wpmd->byte_length += *(*buffptr)++ << 9; + wpmd->byte_length += *(*buffptr)++ << 17; + } + + if (wpmd->id & ID_ODD_SIZE) { + wpmd->id &= ~ID_ODD_SIZE; + wpmd->byte_length--; + } + + if (wpmd->byte_length) { + if (buffend - *buffptr < wpmd->byte_length + (wpmd->byte_length & 1)) { + wpmd->data = NULL; + return FALSE; + } + + wpmd->data = *buffptr; + (*buffptr) += wpmd->byte_length + (wpmd->byte_length & 1); + } + else + wpmd->data = NULL; + + return TRUE; +} + +int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + switch (wpmd->id) { + case ID_DUMMY: + return TRUE; + + case ID_DECORR_TERMS: + return read_decorr_terms (wps, wpmd); + + case ID_DECORR_WEIGHTS: + return read_decorr_weights (wps, wpmd); + + case ID_DECORR_SAMPLES: + return read_decorr_samples (wps, wpmd); + + case ID_ENTROPY_VARS: + return read_entropy_vars (wps, wpmd); + + case ID_HYBRID_PROFILE: + return read_hybrid_profile (wps, wpmd); + + case ID_SHAPING_WEIGHTS: + return read_shaping_info (wps, wpmd); + + case ID_FLOAT_INFO: + return read_float_info (wps, wpmd); + + case ID_INT32_INFO: + return read_int32_info (wps, wpmd); + + case ID_CHANNEL_INFO: + return read_channel_info (wpc, wpmd); + + case ID_CONFIG_BLOCK: + return read_config_info (wpc, wpmd); + + case ID_WV_BITSTREAM: + return init_wv_bitstream (wps, wpmd); + + case ID_WVC_BITSTREAM: + return init_wvc_bitstream (wps, wpmd); + + case ID_WVX_BITSTREAM: + return init_wvx_bitstream (wps, wpmd); + + case ID_RIFF_HEADER: case ID_RIFF_TRAILER: + return read_wrapper_data (wpc, wpmd); + + case ID_MD5_CHECKSUM: + if (wpmd->byte_length == 16) { + memcpy (wpc->config.md5_checksum, wpmd->data, 16); + wpc->config.flags |= CONFIG_MD5_CHECKSUM; + wpc->config.md5_read = 1; + } + + return TRUE; + + default: + return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE; + } +} + +#endif + +#ifdef PACK + +int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end) +{ + uint32_t mdsize = wpmd->byte_length + (wpmd->byte_length & 1); + WavpackHeader *wphdr = (WavpackHeader *) buffer_start; + + if (wpmd->byte_length & 1) + ((char *) wpmd->data) [wpmd->byte_length] = 0; + + mdsize += (wpmd->byte_length > 510) ? 4 : 2; + buffer_start += wphdr->ckSize + 8; + + if (buffer_start + mdsize >= buffer_end) + return FALSE; + + buffer_start [0] = wpmd->id | (wpmd->byte_length & 1 ? ID_ODD_SIZE : 0); + buffer_start [1] = (wpmd->byte_length + 1) >> 1; + + if (wpmd->byte_length > 510) { + buffer_start [0] |= ID_LARGE; + buffer_start [2] = (wpmd->byte_length + 1) >> 9; + buffer_start [3] = (wpmd->byte_length + 1) >> 17; + } + + if (wpmd->data && wpmd->byte_length) { + if (wpmd->byte_length > 510) { + buffer_start [0] |= ID_LARGE; + buffer_start [2] = (wpmd->byte_length + 1) >> 9; + buffer_start [3] = (wpmd->byte_length + 1) >> 17; + memcpy (buffer_start + 4, wpmd->data, mdsize - 4); + } + else + memcpy (buffer_start + 2, wpmd->data, mdsize - 2); + } + + wphdr->ckSize += mdsize; + return TRUE; +} + +int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, uchar id) +{ + WavpackMetadata *mdp; + uchar *src = data; + + while (bcount) { + if (wpc->metacount) { + uint32_t bc = bcount; + + mdp = wpc->metadata + wpc->metacount - 1; + + if (mdp->id == id) { + if (wpc->metabytes + bcount > 1000000) + bc = 1000000 - wpc->metabytes; + + mdp->data = realloc (mdp->data, mdp->byte_length + bc); + memcpy ((char *) mdp->data + mdp->byte_length, src, bc); + mdp->byte_length += bc; + wpc->metabytes += bc; + bcount -= bc; + src += bc; + + if (wpc->metabytes >= 1000000 && !write_metadata_block (wpc)) + return FALSE; + } + } + + if (bcount) { + wpc->metadata = realloc (wpc->metadata, (wpc->metacount + 1) * sizeof (WavpackMetadata)); + mdp = wpc->metadata + wpc->metacount++; + mdp->byte_length = 0; + mdp->data = NULL; + mdp->id = id; + } + } + + return TRUE; +} + +static char *write_metadata (WavpackMetadata *wpmd, char *outdata) +{ + uchar id = wpmd->id, wordlen [3]; + + wordlen [0] = (wpmd->byte_length + 1) >> 1; + wordlen [1] = (wpmd->byte_length + 1) >> 9; + wordlen [2] = (wpmd->byte_length + 1) >> 17; + + if (wpmd->byte_length & 1) { +// ((char *) wpmd->data) [wpmd->byte_length] = 0; + id |= ID_ODD_SIZE; + } + + if (wordlen [1] || wordlen [2]) + id |= ID_LARGE; + + *outdata++ = id; + *outdata++ = wordlen [0]; + + if (id & ID_LARGE) { + *outdata++ = wordlen [1]; + *outdata++ = wordlen [2]; + } + + if (wpmd->data && wpmd->byte_length) { + memcpy (outdata, wpmd->data, wpmd->byte_length); + outdata += wpmd->byte_length; + + if (wpmd->byte_length & 1) + *outdata++ = 0; + } + + return outdata; +} + +int write_metadata_block (WavpackContext *wpc) +{ + char *block_buff, *block_ptr; + WavpackHeader *wphdr; + + if (wpc->metacount) { + int metacount = wpc->metacount, block_size = sizeof (WavpackHeader); + WavpackMetadata *wpmdp = wpc->metadata; + + while (metacount--) { + block_size += wpmdp->byte_length + (wpmdp->byte_length & 1); + block_size += (wpmdp->byte_length > 510) ? 4 : 2; + wpmdp++; + } + + wphdr = (WavpackHeader *) (block_buff = malloc (block_size)); + + CLEAR (*wphdr); + memcpy (wphdr->ckID, "wvpk", 4); + wphdr->total_samples = wpc->total_samples; + wphdr->version = 0x403; + wphdr->ckSize = block_size - 8; + wphdr->block_samples = 0; + + block_ptr = (char *)(wphdr + 1); + + wpmdp = wpc->metadata; + + while (wpc->metacount) { + block_ptr = write_metadata (wpmdp, block_ptr); + wpc->metabytes -= wpmdp->byte_length; + free_metadata (wpmdp++); + wpc->metacount--; + } + + free (wpc->metadata); + wpc->metadata = NULL; + native_to_little_endian ((WavpackHeader *) block_buff, WavpackHeaderFormat); + + if (!wpc->blockout (wpc->wv_out, block_buff, block_size)) { + free (block_buff); + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + return FALSE; + } + + free (block_buff); + } + + return TRUE; +} + +#endif + +void free_metadata (WavpackMetadata *wpmd) +{ + if (wpmd->data) { + free (wpmd->data); + wpmd->data = NULL; + } +} diff --git a/Libraries/WavPack/Files/missing b/Libraries/WavPack/Files/missing new file mode 100755 index 000000000..09edd8844 --- /dev/null +++ b/Libraries/WavPack/Files/missing @@ -0,0 +1,357 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-02-08.22 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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 General Public License for more details. + +# You should have received a copy of the GNU 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/Libraries/WavPack/Files/pack.c b/Libraries/WavPack/Files/pack.c new file mode 100644 index 000000000..46871041d --- /dev/null +++ b/Libraries/WavPack/Files/pack.c @@ -0,0 +1,1413 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// pack.c + +// This module actually handles the compression of the audio data, except for +// the entropy coding which is handled by the words? modules. For efficiency, +// the conversion is isolated to tight loops that handle an entire buffer. + +#include "wavpack.h" + +#include +#include +#include +#include + +// This flag provides faster encoding speed at the expense of more code. The +// improvement applies to 16-bit stereo lossless only. + +#define FAST_ENCODE + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +//////////////////////////////// local tables /////////////////////////////// + +// These two tables specify the characteristics of the decorrelation filters. +// Each term represents one layer of the sequential filter, where positive +// values indicate the relative sample involved from the same channel (1=prev), +// 17 & 18 are special functions using the previous 2 samples, and negative +// values indicate cross channel decorrelation (in stereo only). + +const char default_terms [] = { 18,18,2,3,-2,0 }; +const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,8,-1,18,2,0 }; +const char fast_terms [] = { 17,17,0 }; + +///////////////////////////// executable code //////////////////////////////// + +// This function initializes everything required to pack WavPack bitstreams +// and must be called BEFORE any other function in this module. + +void pack_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags; + struct decorr_pass *dpp; + const char *term_string; + int ti; + + wps->sample_index = 0; + wps->delta_decay = 2.0; + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + + if (wpc->config.flags & CONFIG_AUTO_SHAPING) + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = + (wpc->config.sample_rate < 64000 || (wps->wphdr.flags & CROSS_DECORR)) ? -512L << 16 : 1024L << 16; + else { + int32_t weight = (int32_t) floor (wpc->config.shaping_weight * 1024.0 + 0.5); + + if (weight <= -1000) + weight = -1000; + + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = weight << 16; + } + + if (wpc->config.flags & CONFIG_HIGH_FLAG) + term_string = high_terms; + else if (wpc->config.flags & CONFIG_FAST_FLAG) + term_string = fast_terms; + else + term_string = default_terms; + + for (dpp = wps->decorr_passes, ti = 0; ti < strlen (term_string); ti++) + if (term_string [ti] >= 0 || (flags & CROSS_DECORR)) { + dpp->term = term_string [ti]; + dpp++->delta = 2; + } + else if (!(flags & MONO_FLAG)) { + dpp->term = -3; + dpp++->delta = 2; + } + + wps->num_terms = dpp - wps->decorr_passes; + init_words (wps); +} + +// Allocate room for and copy the decorrelation terms from the decorr_passes +// array into the specified metadata structure. Both the actual term id and +// the delta are packed into single characters. + +void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int tcount = wps->num_terms; + struct decorr_pass *dpp; + char *byteptr; + + byteptr = wpmd->data = malloc (tcount + 1); + wpmd->id = ID_DECORR_TERMS; + + for (dpp = wps->decorr_passes; tcount--; ++dpp) + *byteptr++ = ((dpp->term + 5) & 0x1f) | ((dpp->delta << 5) & 0xe0); + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the decorrelation term weights from the +// decorr_passes array into the specified metadata structure. The weights +// range +/-1024, but are rounded and truncated to fit in signed chars for +// metadata storage. Weights are separate for the two channels + +void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int tcount = wps->num_terms; + struct decorr_pass *dpp; + char *byteptr; + + byteptr = wpmd->data = malloc ((tcount * 2) + 1); + wpmd->id = ID_DECORR_WEIGHTS; + + for (dpp = wps->decorr_passes; tcount--; ++dpp) { + dpp->weight_A = restore_weight (*byteptr++ = store_weight (dpp->weight_A)); + + if (!(wps->wphdr.flags & MONO_FLAG)) + dpp->weight_B = restore_weight (*byteptr++ = store_weight (dpp->weight_B)); + } + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the decorrelation samples from the decorr_passes +// array into the specified metadata structure. The samples are signed 32-bit +// values, but are converted to signed log2 values for storage in metadata. +// Values are stored for both channels and are specified from the first term +// with unspecified samples set to zero. The number of samples stored varies +// with the actual term value, so those must obviously be specified before +// these in the metadata list. Any number of terms can have their samples +// specified from no terms to all the terms, however I have found that +// sending more than the first term's samples is a waste. The "wcount" +// variable can be set to the number of terms to have their samples stored. + +void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int tcount = wps->num_terms, wcount = 1, temp; + struct decorr_pass *dpp; + uchar *byteptr; + + byteptr = wpmd->data = malloc (256); + wpmd->id = ID_DECORR_SAMPLES; + + for (dpp = wps->decorr_passes; tcount--; ++dpp) + if (wcount) { + if (dpp->term > MAX_TERM) { + dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_A [1] = exp2s (temp = log2s (dpp->samples_A [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_B [1] = exp2s (temp = log2s (dpp->samples_B [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + } + else if (dpp->term < 0) { + dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + else { + int m = 0, cnt = dpp->term; + + while (cnt--) { + dpp->samples_A [m] = exp2s (temp = log2s (dpp->samples_A [m])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + dpp->samples_B [m] = exp2s (temp = log2s (dpp->samples_B [m])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + + m++; + } + } + + wcount--; + } + else { + CLEAR (dpp->samples_A); + CLEAR (dpp->samples_B); + } + + wpmd->byte_length = byteptr - (uchar *) wpmd->data; +} + +// Allocate room for and copy the noise shaping info into the specified +// metadata structure. These would normally be written to the +// "correction" file and are used for lossless reconstruction of +// hybrid data. The "delta" parameter is not yet used in encoding as it +// will be part of the "quality" mode. + +void write_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + int temp; + +#if 0 + if (wps->wphdr.block_samples) { + wps->dc.shaping_delta [0] = (-wps->dc.shaping_acc [0] - wps->dc.shaping_acc [0]) / (int32_t) wps->wphdr.block_samples; + wps->dc.shaping_delta [1] = (-wps->dc.shaping_acc [1] - wps->dc.shaping_acc [1]) / (int32_t) wps->wphdr.block_samples; + } +#endif + + byteptr = wpmd->data = malloc (12); + wpmd->id = ID_SHAPING_WEIGHTS; + + wps->dc.error [0] = exp2s (temp = log2s (wps->dc.error [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + wps->dc.shaping_acc [0] = exp2s (temp = log2s (wps->dc.shaping_acc [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->dc.error [1] = exp2s (temp = log2s (wps->dc.error [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + wps->dc.shaping_acc [1] = exp2s (temp = log2s (wps->dc.shaping_acc [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + + if (wps->dc.shaping_delta [0] | wps->dc.shaping_delta [1]) { + wps->dc.shaping_delta [0] = exp2s (temp = log2s (wps->dc.shaping_delta [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->dc.shaping_delta [1] = exp2s (temp = log2s (wps->dc.shaping_delta [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + } + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the int32 data values into the specified +// metadata structure. This data is used for integer data that has more +// than 24 bits of magnitude or, in some cases, it's used to eliminate +// redundant bits from any audio stream. + +void write_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_INT32_INFO; + *byteptr++ = wps->int32_sent_bits; + *byteptr++ = wps->int32_zeros; + *byteptr++ = wps->int32_ones; + *byteptr++ = wps->int32_dups; + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the multichannel information into the specified +// metadata structure. The first byte is the total number of channels and the +// following bytes represent the channel_mask as described for Microsoft +// WAVEFORMATEX. + +void write_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + uint32_t mask = wpc->config.channel_mask; + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_CHANNEL_INFO; + *byteptr++ = wpc->config.num_channels; + + while (mask) { + *byteptr++ = mask; + mask >>= 8; + } + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the configuration information into the specified +// metadata structure. Currently, we just store the upper 3 bytes of +// config.flags and only in the first block of audio data. Note that this is +// for informational purposes not required for playback or decoding (like +// whether high or fast mode was specified). + +void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_CONFIG_BLOCK; + *byteptr++ = (char) (wpc->config.flags >> 8); + *byteptr++ = (char) (wpc->config.flags >> 16); + *byteptr++ = (char) (wpc->config.flags >> 24); + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Pack an entire block of samples (either mono or stereo) into a completed +// WavPack block. This function is actually a shell for pack_samples() and +// performs tasks like handling any shift required by the format, preprocessing +// of floating point data or integer data over 24 bits wide, and implementing +// the "extra" mode (via the extra?.c modules). It is assumed that there is +// sufficient space for the completed block at "wps->blockbuff" and that +// "wps->blockend" points to the end of the available space. A return value of +// FALSE indicates an error. + +static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); +static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); +static int pack_samples (WavpackContext *wpc, int32_t *buffer); + +int pack_block (WavpackContext *wpc, int32_t *buffer) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, sflags = wps->wphdr.flags; + uint32_t sample_count = wps->wphdr.block_samples; + int32_t *orig_data = NULL; + + if (flags & SHIFT_MASK) { + int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; + int mag = (flags & MAG_MASK) >> MAG_LSB; + uint32_t cnt = sample_count; + int32_t *ptr = buffer; + + if (flags & MONO_FLAG) + while (cnt--) + *ptr++ >>= shift; + else + while (cnt--) { + *ptr++ >>= shift; + *ptr++ >>= shift; + } + + if ((mag -= shift) < 0) + flags &= ~MAG_MASK; + else + flags -= (1 << MAG_LSB) * shift; + + wps->wphdr.flags = flags; + } + + if ((flags & FLOAT_DATA) || (flags & MAG_MASK) >> MAG_LSB >= 24) { + if ((!(flags & HYBRID_FLAG) || wpc->wvc_flag) && !(wpc->config.flags & CONFIG_SKIP_WVX)) { + orig_data = malloc (sizeof (f32) * ((flags & MONO_FLAG) ? sample_count : sample_count * 2)); + memcpy (orig_data, buffer, sizeof (f32) * ((flags & MONO_FLAG) ? sample_count : sample_count * 2)); + + if (flags & FLOAT_DATA) { + wps->float_norm_exp = wpc->config.float_norm_exp; + + if (!scan_float_data (wps, (f32 *) buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) { + free (orig_data); + orig_data = NULL; + } + } + else { + if (!scan_int32_data (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) { + free (orig_data); + orig_data = NULL; + } + } + } + else { + if (flags & FLOAT_DATA) { + wps->float_norm_exp = wpc->config.float_norm_exp; + + if (scan_float_data (wps, (f32 *) buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) + wpc->lossy_blocks = TRUE; + } + else if (scan_int32_data (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) + wpc->lossy_blocks = TRUE; + } + + wpc->config.extra_flags |= EXTRA_SCAN_ONLY; + } + else if (wpc->config.extra_flags) + scan_int32_data (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2); + + if (wpc->config.extra_flags) { + if (flags & MONO_FLAG) + analyze_mono (wpc, buffer); + else + analyze_stereo (wpc, buffer); + } + else if (!wps->sample_index || !wps->num_terms) { + wpc->config.extra_flags = EXTRA_SCAN_ONLY; + + if (flags & MONO_FLAG) + analyze_mono (wpc, buffer); + else + analyze_stereo (wpc, buffer); + + wpc->config.extra_flags = 0; + } + + if (!pack_samples (wpc, buffer)) { + wps->wphdr.flags = sflags; + + if (orig_data) + free (orig_data); + + return FALSE; + } + else + wps->wphdr.flags = sflags; + + if (orig_data) { + uint32_t data_count; + uchar *cptr; + + if (wpc->wvc_flag) + cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; + else + cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; + + bs_open_write (&wps->wvxbits, cptr + 8, wpc->wvc_flag ? wps->block2end : wps->blockend); + + if (flags & FLOAT_DATA) + send_float_data (wps, (f32*) orig_data, (flags & MONO_FLAG) ? sample_count : sample_count * 2); + else + send_int32_data (wps, orig_data, (flags & MONO_FLAG) ? sample_count : sample_count * 2); + + data_count = bs_close_write (&wps->wvxbits); + free (orig_data); + + if (data_count) { + if (data_count != (uint32_t) -1) { + *cptr++ = ID_WVX_BITSTREAM | ID_LARGE; + *cptr++ = (data_count += 4) >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + *cptr++ = wps->crc_x; + *cptr++ = wps->crc_x >> 8; + *cptr++ = wps->crc_x >> 16; + *cptr = wps->crc_x >> 24; + + if (wpc->wvc_flag) + ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; + else + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; + } + else + return FALSE; + } + } + + return TRUE; +} + +// Scan a buffer of long integer data and determine whether any redundancy in +// the LSBs can be used to reduce the data's magnitude. If yes, then the +// INT32_DATA flag is set and the int32 parameters are set. If bits must still +// be transmitted literally to get down to 24 bits (which is all the integer +// compression code can handle) then we return TRUE to indicate that a wvx +// stream must be created in either lossless mode. + +static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0; + uint32_t crc = 0xffffffff; + int total_shift = 0; + int32_t *dp, count; + + wps->int32_sent_bits = wps->int32_zeros = wps->int32_ones = wps->int32_dups = 0; + + for (dp = values, count = num_values; count--; dp++) { + crc = crc * 9 + (*dp & 0xffff) * 3 + ((*dp >> 16) & 0xffff); + magdata |= (*dp < 0) ? ~*dp : *dp; + xordata |= *dp ^ -(*dp & 1); + anddata &= *dp; + ordata |= *dp; + } + + wps->crc_x = crc; + wps->wphdr.flags &= ~MAG_MASK; + + while (magdata) { + wps->wphdr.flags += 1 << MAG_LSB; + magdata >>= 1; + } + + if (!((wps->wphdr.flags & MAG_MASK) >> MAG_LSB)) { + wps->wphdr.flags &= ~INT32_DATA; + return FALSE; + } + + if (!(ordata & 1)) + while (!(ordata & 1)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_zeros++; + total_shift++; + ordata >>= 1; + } + else if (anddata & 1) + while (anddata & 1) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_ones++; + total_shift++; + anddata >>= 1; + } + else if (!(xordata & 2)) + while (!(xordata & 2)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_dups++; + total_shift++; + xordata >>= 1; + } + + if (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) > 23) { + wps->int32_sent_bits = ((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) - 23; + total_shift += wps->int32_sent_bits; + wps->wphdr.flags &= ~MAG_MASK; + wps->wphdr.flags += 23 << MAG_LSB; + } + + if (total_shift) { + wps->wphdr.flags |= INT32_DATA; + + for (dp = values, count = num_values; count--; dp++) + *dp >>= total_shift; + } + +#if 0 + if (wps->int32_sent_bits + wps->int32_zeros + wps->int32_ones + wps->int32_dups) + error_line ("sent bits = %d, zeros/ones/dups = %d/%d/%d", wps->int32_sent_bits, + wps->int32_zeros, wps->int32_ones, wps->int32_dups); +#endif + + return wps->int32_sent_bits; +} + +// For the specified buffer values and the int32 parameters stored in "wps", +// send the literal bits required to the "wvxbits" bitstream. + +static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + int sent_bits = wps->int32_sent_bits, pre_shift; + int32_t mask = (1 << sent_bits) - 1; + int32_t count, value, *dp; + + pre_shift = wps->int32_zeros + wps->int32_ones + wps->int32_dups; + + if (sent_bits) + for (dp = values, count = num_values; count--; dp++) { + value = (*dp >> pre_shift) & mask; + putbits (value, sent_bits, &wps->wvxbits); + } +} + +// Pack an entire block of samples (either mono or stereo) into a completed +// WavPack block. It is assumed that there is sufficient space for the +// completed block at "wps->blockbuff" and that "wps->blockend" points to the +// end of the available space. A return value of FALSE indicates an error. +// Any unsent metadata is transmitted first, then required metadata for this +// block is sent, and finally the compressed integer data is sent. If a "wpx" +// stream is required for floating point data or large integer data, then this +// must be handled outside this function. To find out how much data was written +// the caller must look at the ckSize field of the written WavpackHeader, NOT +// the one in the WavpackStream. + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); + +static int pack_samples (WavpackContext *wpc, int32_t *buffer) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t sample_count = wps->wphdr.block_samples; + uint32_t flags = wps->wphdr.flags, data_count; + int mag16 = ((flags & MAG_MASK) >> MAG_LSB) >= 16; + int tcount, lossy = FALSE, m = 0; + double noise_acc = 0.0, noise; + struct decorr_pass *dpp; + WavpackMetadata wpmd; + uint32_t crc, crc2, i; + int32_t *bptr; + + crc = crc2 = 0xffffffff; + + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader)); + + if (wpc->metacount) { + WavpackMetadata *wpmdp = wpc->metadata; + + while (wpc->metacount) { + copy_metadata (wpmdp, wps->blockbuff, wps->blockend); + wpc->metabytes -= wpmdp->byte_length; + free_metadata (wpmdp++); + wpc->metacount--; + } + + free (wpc->metadata); + wpc->metadata = NULL; + } + + if (!sample_count) + return TRUE; + + write_decorr_terms (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_decorr_weights (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_decorr_samples (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_entropy_vars (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + if (flags & HYBRID_FLAG) { + write_hybrid_profile (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & FLOAT_DATA) { + write_float_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & INT32_DATA) { + write_int32_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if ((flags & INITIAL_BLOCK) && + (wpc->config.num_channels > 2 || + wpc->config.channel_mask != 0x5 - wpc->config.num_channels)) { + write_channel_info (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if ((flags & INITIAL_BLOCK) && !wps->sample_index) { + write_config_info (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend); + + if (wpc->wvc_flag) { + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader)); + + if (flags & HYBRID_SHAPE) { + write_shaping_info (wps, &wpmd); + copy_metadata (&wpmd, wps->block2buff, wps->block2end); + free_metadata (&wpmd); + } + + bs_open_write (&wps->wvcbits, wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 12, wps->block2end); + } + + /////////////////////// handle lossless mono mode ///////////////////////// + + if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t code; + + crc = crc * 3 + (code = *bptr++); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = code; + } + else { + sam = dpp->samples_A [m]; + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = code; + } + + code -= apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, code); + } + + m = (m + 1) & (MAX_TERM - 1); + send_word_lossless (wps, code, 0); + } + + //////////////////// handle the lossless stereo mode ////////////////////// + +#ifdef FAST_ENCODE + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) { + int32_t *eptr = buffer + (sample_count * 2), sam_A, sam_B; + + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) { + crc = crc * 9 + bptr [0] * 3 + bptr [1]; + bptr [1] += ((bptr [0] -= bptr [1]) >> 1); + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) + crc = crc * 9 + bptr [0] * 3 + bptr [1]; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (((flags & MAG_MASK) >> MAG_LSB) >= 16) + decorr_stereo_pass (dpp, buffer, sample_count); + else if (dpp->delta != 2) + decorr_stereo_pass_i (dpp, buffer, sample_count); + else + decorr_stereo_pass_id2 (dpp, buffer, sample_count); + + for (bptr = buffer; bptr < eptr; bptr += 2) { + send_word_lossless (wps, bptr [0], 0); + send_word_lossless (wps, bptr [1], 1); + } + + m = sample_count & (MAX_TERM - 1); + } +#else + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i, bptr += 2) { + int32_t left, right, sam_A, sam_B; + + crc = crc * 3 + (left = bptr [0]); + crc = crc * 3 + (right = bptr [1]); + + if (flags & JOINT_STEREO) + right += ((left -= right) >> 1); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) { + if (dpp->term > 0) { + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_A [0] = left; + dpp->samples_B [0] = right; + } + else { + int k = (m + dpp->term) & (MAX_TERM - 1); + + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + dpp->samples_A [k] = left; + dpp->samples_B [k] = right; + } + + left -= apply_weight (dpp->weight_A, sam_A); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + } + else { + sam_A = (dpp->term == -2) ? right : dpp->samples_A [0]; + sam_B = (dpp->term == -1) ? left : dpp->samples_B [0]; + dpp->samples_A [0] = right; + dpp->samples_B [0] = left; + left -= apply_weight (dpp->weight_A, sam_A); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + } + } + + m = (m + 1) & (MAX_TERM - 1); + send_word_lossless (wps, left, 0); + send_word_lossless (wps, right, 1); + } +#endif + + /////////////////// handle the lossy/hybrid mono mode ///////////////////// + + else if ((flags & HYBRID_FLAG) && (flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t code, temp; + + crc2 = crc2 * 3 + (code = *bptr++); + + if (flags & HYBRID_SHAPE) { + int shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = -code; + code += temp; + } + else + wps->dc.error [0] = -(code += temp); + } + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); + } + else + code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); + + code = send_word (wps, code, 0); + + while (--dpp >= wps->decorr_passes) { + if (dpp->term > MAX_TERM) { + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], code); + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = (code += dpp->aweight_A); + } + else { + int32_t sam = dpp->samples_A [m]; + + update_weight (dpp->weight_A, dpp->delta, sam, code); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = (code += dpp->aweight_A); + } + } + + wps->dc.error [0] += code; + m = (m + 1) & (MAX_TERM - 1); + + if ((crc = crc * 3 + code) != crc2) + lossy = TRUE; + + if (wpc->config.flags & CONFIG_CALC_NOISE) { + noise = code - bptr [-1]; + + noise_acc += noise *= noise; + wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); + + if (wps->dc.noise_ave > wps->dc.noise_max) + wps->dc.noise_max = wps->dc.noise_ave; + } + } + + /////////////////// handle the lossy/hybrid stereo mode /////////////////// + + else if ((flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, temp; + int shaping_weight; + + left = *bptr++; + crc2 = (crc2 * 3 + left) * 3 + (right = *bptr++); + + if (flags & HYBRID_SHAPE) { + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = -left; + left += temp; + } + else + wps->dc.error [0] = -(left += temp); + + shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16; + temp = -apply_weight (shaping_weight, wps->dc.error [1]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [1]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [1] = -right; + right += temp; + } + else + wps->dc.error [1] = -(right += temp); + } + + if (flags & JOINT_STEREO) + right += ((left -= right) >> 1); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_B [2] = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_B [2] = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [2])); + } + else if (dpp->term > 0) { + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [m])); + } + else { + if (dpp->term == -1) + dpp->samples_B [0] = left; + else if (dpp->term == -2) + dpp->samples_A [0] = right; + + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0])); + } +#if 0 +if (labs (left) > 60000000 || labs (right) > 60000000) + error_line ("sending %d, %d; samples = %d, %d", left, right, bptr [-2], bptr [-1]); +#endif + left = send_word (wps, left, 0); + right = send_word (wps, right, 1); + + while (--dpp >= wps->decorr_passes) + if (dpp->term > MAX_TERM) { + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], left); + update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [2], right); + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = (left += dpp->aweight_A); + dpp->samples_B [0] = (right += dpp->aweight_B); + } + else if (dpp->term > 0) { + int k = (m + dpp->term) & (MAX_TERM - 1); + + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [m], left); + dpp->samples_A [k] = (left += dpp->aweight_A); + + update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [m], right); + dpp->samples_B [k] = (right += dpp->aweight_B); + } + else { + if (dpp->term == -1) { + dpp->samples_B [0] = left + dpp->aweight_A; + dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0]); + } + else if (dpp->term == -2) { + dpp->samples_A [0] = right + dpp->aweight_B; + dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0]); + } + + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right); + dpp->samples_B [0] = (left += dpp->aweight_A); + dpp->samples_A [0] = (right += dpp->aweight_B); + } + + if (flags & JOINT_STEREO) + left += (right -= (left >> 1)); + + wps->dc.error [0] += left; + wps->dc.error [1] += right; + m = (m + 1) & (MAX_TERM - 1); + + if ((crc = (crc * 3 + left) * 3 + right) != crc2) + lossy = TRUE; + + if (wpc->config.flags & CONFIG_CALC_NOISE) { + noise = (double)(left - bptr [-2]) * (left - bptr [-2]); + noise += (double)(right - bptr [-1]) * (right - bptr [-1]); + + noise_acc += noise /= 2.0; + wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); + + if (wps->dc.noise_ave > wps->dc.noise_max) + wps->dc.noise_max = wps->dc.noise_ave; + } + } + + if (m) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0 && dpp->term <= MAX_TERM) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + if (wpc->config.flags & CONFIG_CALC_NOISE) + wps->dc.noise_sum += noise_acc; + + flush_word (wps); + data_count = bs_close_write (&wps->wvbits); + + if (data_count) { + if (data_count != (uint32_t) -1) { + uchar *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; + + *cptr++ = ID_WV_BITSTREAM | ID_LARGE; + *cptr++ = data_count >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; + } + else + return FALSE; + } + + ((WavpackHeader *) wps->blockbuff)->crc = crc; + + if (wpc->wvc_flag) { + data_count = bs_close_write (&wps->wvcbits); + + if (data_count && lossy) { + if (data_count != (uint32_t) -1) { + uchar *cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; + + *cptr++ = ID_WVC_BITSTREAM | ID_LARGE; + *cptr++ = data_count >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; + } + else + return FALSE; + } + + ((WavpackHeader *) wps->block2buff)->crc = crc2; + } + else if (lossy) + wpc->lossy_blocks = TRUE; + + wps->sample_index += sample_count; + return TRUE; +} + +#ifdef FAST_ENCODE + +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 8: + for (m = 0, bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [m] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = dpp->samples_B [m]; + dpp->samples_B [m] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + dpp->samples_A [k] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, dpp->samples_A [m]); + update_weight_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [m], bptr [0]); + + dpp->samples_B [k] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, dpp->samples_B [m]); + update_weight_d2 (dpp->weight_B, dpp->delta, dpp->samples_B [m], bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = bptr [0]; + dpp->samples_A [0] = bptr [1]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [1]; + sam_B = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + dpp->samples_A [0] = bptr [1]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + } +} + +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = dpp->samples_B [m]; + dpp->samples_B [k] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = bptr [0]; + dpp->samples_A [0] = bptr [1]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [1]; + sam_B = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + dpp->samples_A [0] = bptr [1]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + } +} + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = dpp->samples_B [m]; + dpp->samples_B [k] = bptr [1]; + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = bptr [0]; + dpp->samples_A [0] = bptr [1]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [1]; + sam_B = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + dpp->samples_A [0] = bptr [1]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + } +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function returns the accumulated RMS noise as a double if the // +// CALC_NOISE bit was set in the WavPack header. The peak noise can also be // +// returned if desired. See wavpack.c for the calculations required to // +// convert this into decibels of noise below full scale. // +////////////////////////////////////////////////////////////////////////////// + +double pack_noise (WavpackContext *wpc, double *peak) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + if (peak) + *peak = wps->dc.noise_max; + + return wps->dc.noise_sum; +} diff --git a/Libraries/WavPack/Files/unpack.c b/Libraries/WavPack/Files/unpack.c new file mode 100644 index 000000000..2e1f0e653 --- /dev/null +++ b/Libraries/WavPack/Files/unpack.c @@ -0,0 +1,1453 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack.c + +// This module actually handles the decompression of the audio data, except +// for the entropy decoding which is handled by the words? modules. For +// maximum efficiency, the conversion is isolated to tight loops that handle +// an entire buffer. + +#include "wavpack.h" + +#include +#include +#include +#include + +// This flag provides faster decoding speed at the expense of more code. The +// improvement applies to 16-bit stereo lossless only. + +#define FAST_DECODE + +#define LOSSY_MUTE + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +///////////////////////////// executable code //////////////////////////////// + +// This function initializes everything required to unpack a WavPack block +// and must be called before unpack_samples() is called to obtain audio data. +// It is assumed that the WavpackHeader has been read into the wps->wphdr +// (in the current WavpackStream) and that the entire block has been read at +// wps->blockbuff. If a correction file is available (wpc->wvc_flag = TRUE) +// then the corresponding correction block must be read into wps->block2buff +// and its WavpackHeader has overwritten the header at wps->wphdr. This is +// where all the metadata blocks are scanned including those that contain +// bitstream data. + +int unpack_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uchar *blockptr, *block2ptr; + WavpackMetadata wpmd; + + if (wps->wphdr.block_samples && wps->wphdr.block_index != (uint32_t) -1) + wps->sample_index = wps->wphdr.block_index; + + wps->mute_error = FALSE; + wps->crc = wps->crc_x = 0xffffffff; + CLEAR (wps->wvbits); + CLEAR (wps->wvcbits); + CLEAR (wps->wvxbits); + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + CLEAR (wps->w); + + blockptr = wps->blockbuff + sizeof (WavpackHeader); + + while (read_metadata_buff (&wpmd, wps->blockbuff, &blockptr)) + if (!process_metadata (wpc, &wpmd)) { + sprintf (wpc->error_message, "invalid metadata %2x!", wpmd.id); + return FALSE; + } + + block2ptr = wps->block2buff + sizeof (WavpackHeader); + + while (wpc->wvc_flag && wps->wphdr.block_samples && read_metadata_buff (&wpmd, wps->block2buff, &block2ptr)) + if (!process_metadata (wpc, &wpmd)) { + sprintf (wpc->error_message, "invalid metadata %2x in wvc file!", wpmd.id); + return FALSE; + } + + if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) { + if (bs_is_open (&wps->wvcbits)) + strcpy (wpc->error_message, "can't unpack correction files alone!"); + + return FALSE; + } + + if (wps->wphdr.block_samples && !bs_is_open (&wps->wvxbits)) { + if ((wps->wphdr.flags & INT32_DATA) && wps->int32_sent_bits) + wpc->lossy_blocks = TRUE; + + if ((wps->wphdr.flags & FLOAT_DATA) && + wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME)) + wpc->lossy_blocks = TRUE; + } + + return TRUE; +} + +// This function initialzes the main bitstream for audio samples, which must +// be in the "wv" file. + +int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + bs_open_read (&wps->wvbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// This function initialzes the "correction" bitstream for audio samples, +// which currently must be in the "wvc" file. + +int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + bs_open_read (&wps->wvcbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// This function initialzes the "extra" bitstream for audio samples which +// contains the information required to losslessly decompress 32-bit float data +// or integer data that exceeds 24 bits. This bitstream is in the "wv" file +// for pure lossless data or the "wvc" file for hybrid lossless. This data +// would not be used for hybrid lossy mode. There is also a 32-bit CRC stored +// in the first 4 bytes of these blocks. + +int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *cp = wpmd->data; + + wps->crc_wvx = *cp++; + wps->crc_wvx |= (int32_t) *cp++ << 8; + wps->crc_wvx |= (int32_t) *cp++ << 16; + wps->crc_wvx |= (int32_t) *cp++ << 24; + + bs_open_read (&wps->wvxbits, cp, (char *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// Read decorrelation terms from specified metadata block into the +// decorr_passes array. The terms range from -3 to 8, plus 17 & 18; +// other values are reserved and generate errors for now. The delta +// ranges from 0 to 7 with all values valid. Note that the terms are +// stored in the opposite order in the decorr_passes array compared +// to packing. + +int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int termcnt = wpmd->byte_length; + uchar *byteptr = wpmd->data; + struct decorr_pass *dpp; + + if (termcnt > MAX_NTERMS) + return FALSE; + + wps->num_terms = termcnt; + + for (dpp = wps->decorr_passes + termcnt - 1; termcnt--; dpp--) { + dpp->term = (int)(*byteptr & 0x1f) - 5; + dpp->delta = (*byteptr++ >> 5) & 0x7; + + if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18) + return FALSE; + } + + return TRUE; +} + +// Read decorrelation weights from specified metadata block into the +// decorr_passes array. The weights range +/-1024, but are rounded and +// truncated to fit in signed chars for metadata storage. Weights are +// separate for the two channels and are specified from the "last" term +// (first during encode). Unspecified weights are set to zero. + +int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int termcnt = wpmd->byte_length, tcount; + char *byteptr = wpmd->data; + struct decorr_pass *dpp; + + if (!(wps->wphdr.flags & MONO_FLAG)) + termcnt /= 2; + + if (termcnt > wps->num_terms) + return FALSE; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + dpp->weight_A = dpp->weight_B = 0; + + while (--dpp >= wps->decorr_passes && termcnt--) { + dpp->weight_A = restore_weight (*byteptr++); + + if (!(wps->wphdr.flags & MONO_FLAG)) + dpp->weight_B = restore_weight (*byteptr++); + } + + return TRUE; +} + +// Read decorrelation samples from specified metadata block into the +// decorr_passes array. The samples are signed 32-bit values, but are +// converted to signed log2 values for storage in metadata. Values are +// stored for both channels and are specified from the "last" term +// (first during encode) with unspecified samples set to zero. The +// number of samples stored varies with the actual term value, so +// those must obviously come first in the metadata. + +int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *byteptr = wpmd->data; + uchar *endptr = byteptr + wpmd->byte_length; + struct decorr_pass *dpp; + int tcount; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + CLEAR (dpp->samples_A); + CLEAR (dpp->samples_B); + } + + if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) { + wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->dc.error [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + } + + while (dpp-- > wps->decorr_passes && byteptr < endptr) + if (dpp->term > MAX_TERM) { + dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_A [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + dpp->samples_B [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + } + else if (dpp->term < 0) { + dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + else { + int m = 0, cnt = dpp->term; + + while (cnt--) { + dpp->samples_A [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + dpp->samples_B [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + + m++; + } + } + + return byteptr == endptr; +} + +// Read the shaping weights from specified metadata block into the +// WavpackStream structure. Note that there must be two values (even +// for mono streams) and that the values are stored in the same +// manner as decorrelation weights. These would normally be read from +// the "correction" file and are used for lossless reconstruction of +// hybrid data. + +int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + if (wpmd->byte_length == 2) { + char *byteptr = wpmd->data; + + wps->dc.shaping_acc [0] = (int32_t) restore_weight (*byteptr++) << 16; + wps->dc.shaping_acc [1] = (int32_t) restore_weight (*byteptr++) << 16; + return TRUE; + } + else if (wpmd->byte_length >= (wps->wphdr.flags & MONO_FLAG ? 4 : 8)) { + uchar *byteptr = wpmd->data; + + wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->dc.error [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + + if (wpmd->byte_length == (wps->wphdr.flags & MONO_FLAG ? 6 : 12)) { + wps->dc.shaping_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + + if (!(wps->wphdr.flags & MONO_FLAG)) + wps->dc.shaping_delta [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + } + + return TRUE; + } + + return FALSE; +} + +// Read the int32 data from the specified metadata into the specified stream. +// This data is used for integer data that has more than 24 bits of magnitude +// or, in some cases, used to eliminate redundant bits from any audio stream. + +int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + char *byteptr = wpmd->data; + + if (bytecnt != 4) + return FALSE; + + wps->int32_sent_bits = *byteptr++; + wps->int32_zeros = *byteptr++; + wps->int32_ones = *byteptr++; + wps->int32_dups = *byteptr; + + return TRUE; +} + +// Read multichannel information from metadata. The first byte is the total +// number of channels and the following bytes represent the channel_mask +// as described for Microsoft WAVEFORMATEX. + +int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length, shift = 0; + char *byteptr = wpmd->data; + uint32_t mask = 0; + + if (!bytecnt || bytecnt > 5) + return FALSE; + + wpc->config.num_channels = *byteptr++; + + while (--bytecnt) { + mask |= (uint32_t) *byteptr++ << shift; + shift += 8; + } + + wpc->config.channel_mask = mask; + return TRUE; +} + +// Read configuration information from metadata. + +int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + uchar *byteptr = wpmd->data; + + if (bytecnt >= 3) { + wpc->config.flags &= 0xff; + wpc->config.flags |= (int32_t) *byteptr++ << 8; + wpc->config.flags |= (int32_t) *byteptr++ << 16; + wpc->config.flags |= (int32_t) *byteptr << 24; + } + + return TRUE; +} + +// Read wrapper data from metadata. Currently, this consists of the RIFF +// header and trailer that wav files contain around the audio data but could +// be used for other formats as well. Because WavPack files contain all the +// information required for decoding and playback, this data can probably +// be ignored except when an exact wavefile restoration is needed. + +int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + wpmd->byte_length); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, wpmd->data, wpmd->byte_length); + wpc->wrapper_bytes += wpmd->byte_length; + } + + return TRUE; +} + +#ifdef UNPACK + +// This monster actually unpacks the WavPack bitstream(s) into the specified +// buffer as 32-bit integers or floats (depending on orignal data). Lossy +// samples will be clipped to their original limits (i.e. 8-bit samples are +// clipped to -128/+127) but are still returned in longs. It is up to the +// caller to potentially reformat this for the final output including any +// multichannel distribution, block alignment or endian compensation. The +// function unpack_init() must have been called and the entire WavPack block +// must still be visible (although wps->blockbuff will not be accessed again). +// For maximum clarity, the function is broken up into segments that handle +// various modes. This makes for a few extra infrequent flag checks, but +// makes the code easier to follow because the nesting does not become so +// deep. For maximum efficiency, the conversion is isolated to tight loops +// that handle an entire buffer. The function returns the total number of +// samples unpacked, which can be less than the number requested if an error +// occurs or the end of the block is reached. + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id0 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id1 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); + +static void fixup_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); + +int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, crc = wps->crc, i; + int32_t mute_limit = (1L << ((flags & MAG_MASK) >> MAG_LSB)) + 2; + int32_t correction [2], read_word, *bptr; + struct decorr_pass *dpp; + int tcount, m = 0; + + if (wps->sample_index + sample_count > wps->wphdr.block_index + wps->wphdr.block_samples) + sample_count = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; + + if (wps->mute_error) { + memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); + wps->sample_index += sample_count; + return sample_count; + } + + if ((flags & HYBRID_FLAG) && !wpc->wvc_flag) + mute_limit *= 2; + + ///////////////// handle version 4 lossless mono data ///////////////////// + + if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word_lossless (wps, 0)) == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam, temp; + int k; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + k = 0; + } + else { + sam = dpp->samples_A [m]; + k = (m + dpp->term) & (MAX_TERM - 1); + } + + temp = apply_weight (dpp->weight_A, sam) + read_word; + update_weight (dpp->weight_A, dpp->delta, sam, read_word); + dpp->samples_A [k] = read_word = temp; + } + + if (labs (read_word) > mute_limit) + break; + + m = (m + 1) & (MAX_TERM - 1); + crc = crc * 3 + read_word; + *bptr++ = read_word; + } + + //////////////// handle version 4 lossless stereo data //////////////////// + + else if (!wpc->wvc_flag && !(flags & MONO_FLAG)) { + int32_t *eptr = buffer + (sample_count * 2); + + i = sample_count; + + if (flags & HYBRID_FLAG) { + for (bptr = buffer; bptr < eptr; bptr += 2) + if ((bptr [0] = get_word (wps, 0, NULL)) == WORD_EOF || + (bptr [1] = get_word (wps, 1, NULL)) == WORD_EOF) { + i = (bptr - buffer) / 2; + break; + } + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) + if ((bptr [0] = get_word_lossless (wps, 0)) == WORD_EOF || + (bptr [1] = get_word_lossless (wps, 1)) == WORD_EOF) { + i = (bptr - buffer) / 2; + break; + } + +#ifdef FAST_DECODE + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (((flags & MAG_MASK) >> MAG_LSB) >= 16) + decorr_stereo_pass (dpp, buffer, sample_count); + else if (dpp->delta > 2) + decorr_stereo_pass_i (dpp, buffer, sample_count); + else if (dpp->delta == 2) + decorr_stereo_pass_id2 (dpp, buffer, sample_count); + else if (dpp->delta == 1) + decorr_stereo_pass_id1 (dpp, buffer, sample_count); + else + decorr_stereo_pass_id0 (dpp, buffer, sample_count); +#else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + decorr_stereo_pass (dpp, buffer, sample_count); +#endif + + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += (bptr [1] -= (bptr [0] >> 1)); + + if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { + i = (bptr - buffer) / 2; + break; + } + + crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) { + if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { + i = (bptr - buffer) / 2; + break; + } + + crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; + } + + m = sample_count & (MAX_TERM - 1); + } + + //////////////// handle version 4 lossy/hybrid mono data ////////////////// + + else if ((flags & HYBRID_FLAG) && (flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word (wps, 0, correction)) == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam, temp; + int k; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + k = 0; + } + else { + sam = dpp->samples_A [m]; + k = (m + dpp->term) & (MAX_TERM - 1); + } + + temp = apply_weight (dpp->weight_A, sam) + read_word; + update_weight (dpp->weight_A, dpp->delta, sam, read_word); + dpp->samples_A [k] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (wpc->wvc_flag) { + if (flags & HYBRID_SHAPE) { + int shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + int32_t temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = temp - correction [0]; + } + else + wps->dc.error [0] = -correction [0]; + + read_word += correction [0] - temp; + } + else + read_word += correction [0]; + } + + crc = crc * 3 + read_word; + +#ifdef LOSSY_MUTE + if (labs (read_word) > mute_limit) + break; +#endif + *bptr++ = read_word; + } + + //////////////// handle version 4 lossy/hybrid stereo data //////////////// + + else if (wpc->wvc_flag && !(flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, left_c, right_c, left2, right2; + + if ((left = get_word (wps, 0, correction)) == WORD_EOF || + (right = get_word (wps, 1, correction + 1)) == WORD_EOF) + break; + + if (flags & CROSS_DECORR) { + left_c = left + correction [0]; + right_c = right + correction [1]; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam_A, sam_B; + + if (dpp->term > 0) { + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + } + else { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + } + + left_c += apply_weight (dpp->weight_A, sam_A); + right_c += apply_weight (dpp->weight_B, sam_B); + } + else if (dpp->term == -1) { + left_c += apply_weight (dpp->weight_A, dpp->samples_A [0]); + right_c += apply_weight (dpp->weight_B, left_c); + } + else { + right_c += apply_weight (dpp->weight_B, dpp->samples_B [0]); + + if (dpp->term == -3) + left_c += apply_weight (dpp->weight_A, dpp->samples_A [0]); + else + left_c += apply_weight (dpp->weight_A, right_c); + } + } + + if (flags & JOINT_STEREO) + left_c += (right_c -= (left_c >> 1)); + } + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam_A, sam_B; + + if (dpp->term > 0) { + int k; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + k = 0; + } + else { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + k = (m + dpp->term) & (MAX_TERM - 1); + } + + left2 = apply_weight (dpp->weight_A, sam_A) + left; + right2 = apply_weight (dpp->weight_B, sam_B) + right; + + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight (dpp->weight_B, left2); + update_weight_clip (dpp->weight_B, dpp->delta, left2, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right); + right = right2; + + if (dpp->term == -3) { + right2 = dpp->samples_A [0]; + dpp->samples_A [0] = right; + } + + left2 = left + apply_weight (dpp->weight_A, right2); + update_weight_clip (dpp->weight_A, dpp->delta, right2, left); + dpp->samples_B [0] = left = left2; + } + } + + m = (m + 1) & (MAX_TERM - 1); + + if (!(flags & CROSS_DECORR)) { + left_c = left + correction [0]; + right_c = right + correction [1]; + + if (flags & JOINT_STEREO) + left_c += (right_c -= (left_c >> 1)); + } + + if (flags & JOINT_STEREO) + left += (right -= (left >> 1)); + + if (flags & HYBRID_SHAPE) { + int shaping_weight; + int32_t temp; + + correction [0] = left_c - left; + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = temp - correction [0]; + } + else + wps->dc.error [0] = -correction [0]; + + left = left_c - temp; + correction [1] = right_c - right; + shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16; + temp = -apply_weight (shaping_weight, wps->dc.error [1]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [1]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [1] = temp - correction [1]; + } + else + wps->dc.error [1] = -correction [1]; + + right = right_c - temp; + } + else { + left = left_c; + right = right_c; + } + +#ifdef LOSSY_MUTE + if (labs (left) > mute_limit || labs (right) > mute_limit) + break; +#endif + crc = (crc * 3 + left) * 3 + right; + *bptr++ = left; + *bptr++ = right; + } + + if (i != sample_count) { + memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); + wps->mute_error = TRUE; + i = sample_count; + + if (bs_is_open (&wps->wvxbits)) + bs_close_read (&wps->wvxbits); + } + + if (m) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0 && dpp->term <= MAX_TERM) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + fixup_samples (wpc, buffer, i); + + if ((flags & FLOAT_DATA) && (wpc->open_flags & OPEN_NORMALIZE)) + float_normalize (buffer, (flags & MONO_FLAG) ? i : i * 2, + 127 - wps->float_norm_exp + wpc->norm_offset); + + wps->sample_index += i; + wps->crc = crc; + + return i; +} + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + bptr [1] = dpp->samples_B [k]; + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight (dpp->weight_B, sam_A); + update_weight_clip (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight (dpp->weight_A, sam_B); + update_weight_clip (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [0] = dpp->samples_B [0] = sam_A; + bptr [1] = dpp->samples_A [0] = sam_B; + } + + break; + } +} + +#ifdef FAST_DECODE + +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + bptr [1] = dpp->samples_B [k]; + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); + update_weight_clip (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); + update_weight_clip (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [0] = dpp->samples_B [0] = sam_A; + bptr [1] = dpp->samples_A [0] = sam_B; + } + + break; + } +} + +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + bptr [1] = dpp->samples_B [k]; + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [0] = dpp->samples_B [0] = sam_A; + bptr [1] = dpp->samples_A [0] = sam_B; + } + + break; + } +} + +static void decorr_stereo_pass_id1 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + bptr [1] = dpp->samples_B [k]; + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d1 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); + update_weight_clip_d1 (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d1 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); + update_weight_clip_d1 (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d1 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d1 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [0] = dpp->samples_B [0] = sam_A; + bptr [1] = dpp->samples_A [0] = sam_B; + } + + break; + } +} + +static void decorr_stereo_pass_id0 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = bptr [0] += apply_weight_i (dpp->weight_A, sam_A); + dpp->samples_B [0] = bptr [1] += apply_weight_i (dpp->weight_B, sam_B); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = bptr [0] += apply_weight_i (dpp->weight_A, sam_A); + dpp->samples_B [0] = bptr [1] += apply_weight_i (dpp->weight_B, sam_B); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + dpp->samples_A [k] = bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [m]); + dpp->samples_B [k] = bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [m]); + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + dpp->samples_A [0] = bptr [1] += apply_weight_i (dpp->weight_B, bptr [0]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + dpp->samples_B [0] = bptr [0] += apply_weight_i (dpp->weight_A, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + dpp->samples_A [0] = bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + dpp->samples_B [0] = bptr [0]; + } + + break; + } +} + +#endif + +// This is a helper function for unpack_samples() that applies several final +// operations. First, if the data is 32-bit float data, then that conversion +// is done in the float.c module (whether lossy or lossless) and we return. +// Otherwise, if the extended integer data applies, then that operation is +// executed first. If the unpacked data is lossy (and not corrected) then +// it is clipped and shifted in a single operation. Otherwise, if it's +// lossless then the last step is to apply the final shift (if any). + +static void fixup_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags; + int lossy_flag = (flags & HYBRID_FLAG) && !wpc->wvc_flag; + int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; + + if (flags & FLOAT_DATA) { + float_values (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2); + return; + } + + if (flags & INT32_DATA) { + uint32_t count = (flags & MONO_FLAG) ? sample_count : sample_count * 2; + int sent_bits = wps->int32_sent_bits, zeros = wps->int32_zeros; + int ones = wps->int32_ones, dups = wps->int32_dups; + uint32_t data, mask = (1 << sent_bits) - 1; + int32_t *dptr = buffer; + + if (bs_is_open (&wps->wvxbits)) { + uint32_t crc = wps->crc_x; + + while (count--) { +// if (sent_bits) { + getbits (&data, sent_bits, &wps->wvxbits); + *dptr = (*dptr << sent_bits) | (data & mask); +// } + + if (zeros) + *dptr <<= zeros; + else if (ones) + *dptr = ((*dptr + 1) << ones) - 1; + else if (dups) + *dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1); + + crc = crc * 9 + (*dptr & 0xffff) * 3 + ((*dptr >> 16) & 0xffff); + dptr++; + } + + wps->crc_x = crc; + } + else if (!sent_bits && (zeros + ones + dups)) { + while (lossy_flag && (flags & BYTES_STORED) == 3 && shift < 8) { + if (zeros) + zeros--; + else if (ones) + ones--; + else if (dups) + dups--; + else + break; + + shift++; + } + + while (count--) { + if (zeros) + *dptr <<= zeros; + else if (ones) + *dptr = ((*dptr + 1) << ones) - 1; + else if (dups) + *dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1); + + dptr++; + } + } + else + shift += zeros + sent_bits + ones + dups; + } + + if (lossy_flag) { + int32_t min_value, max_value, min_shifted, max_shifted; + + switch (flags & BYTES_STORED) { + case 0: + min_shifted = (min_value = -128 >> shift) << shift; + max_shifted = (max_value = 127 >> shift) << shift; + break; + + case 1: + min_shifted = (min_value = -32768 >> shift) << shift; + max_shifted = (max_value = 32767 >> shift) << shift; + break; + + case 2: + min_shifted = (min_value = -8388608 >> shift) << shift; + max_shifted = (max_value = 8388607 >> shift) << shift; + break; + + case 3: + min_shifted = (min_value = (int32_t) 0x80000000 >> shift) << shift; + max_shifted = (max_value = (int32_t) 0x7fffffff >> shift) << shift; + break; + } + + if (!(flags & MONO_FLAG)) + sample_count *= 2; + + while (sample_count--) { + if (*buffer < min_value) + *buffer++ = min_shifted; + else if (*buffer > max_value) + *buffer++ = max_shifted; + else + *buffer++ <<= shift; + } + } + else if (shift) { + if (!(flags & MONO_FLAG)) + sample_count *= 2; + + while (sample_count--) + *buffer++ <<= shift; + } +} + +// This function checks the crc value(s) for an unpacked block, returning the +// number of actual crc errors detected for the block. The block must be +// completely unpacked before this test is valid. For losslessly unpacked +// blocks of float or extended integer data the extended crc is also checked. +// Note that WavPack's crc is not a CCITT approved polynomial algorithm, but +// is a much simpler method that is virtually as robust for real world data. + +int check_crc_error (WavpackContext *wpc) +{ + int result = 0, stream; + + for (stream = 0; stream < wpc->num_streams; stream++) { + WavpackStream *wps = wpc->streams [stream]; + + if (wps->crc != wps->wphdr.crc) + ++result; + else if (bs_is_open (&wps->wvxbits) && wps->crc_x != wps->crc_wvx) + ++result; + } + + return result; +} + +#endif diff --git a/Libraries/WavPack/Files/unpack3.c b/Libraries/WavPack/Files/unpack3.c new file mode 100644 index 000000000..8f8e0c5d0 --- /dev/null +++ b/Libraries/WavPack/Files/unpack3.c @@ -0,0 +1,2010 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack3.c + +// This module provides unpacking for WavPack files prior to version 4.0, +// not including "raw" files. As these modes are all obsolete and are no +// longer written, this code will not be fully documented other than the +// global functions. However, full documenation is provided in the version +// 3.97 source code. + +#include +#include +#include +#include + +#include "wavpack.h" +#include "unpack3.h" + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +static void unpack_init3 (WavpackStream3 *wps); +static int bs_open_read3 (Bitstream3 *bs, stream_reader *reader, void *id); +static void bs_close_read3 (Bitstream3 *bs); +#ifdef SEEKING +static void bs_restore3 (Bitstream3 *bs); +#endif + +// This provides an extension to the WavpackOpenFileRead () function contained +// in the wputils.c module. It is assumed that an 'R' had been read as the +// first character of the file/stream (indicating a non-raw pre version 4.0 +// WavPack file) and had been pushed back onto the stream (or simply seeked +// back to). + +WavpackContext *open_file3 (WavpackContext *wpc, char *error) +{ + RiffChunkHeader RiffChunkHeader; + ChunkHeader ChunkHeader; + WavpackHeader3 wphdr; + WavpackStream3 *wps; + WaveHeader3 wavhdr; + + wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3)); + CLEAR (*wps); + + if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) != + sizeof (RiffChunkHeader)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) { + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = malloc (wpc->wrapper_bytes = sizeof (RiffChunkHeader)); + memcpy (wpc->wrapper_data, &RiffChunkHeader, sizeof (RiffChunkHeader)); + } + + // If the first chunk is a wave RIFF header, then read the various chunks + // until we get to the "data" chunk (and WavPack header should follow). If + // the first chunk is not a RIFF, then we assume a "raw" WavPack file and + // the WavPack header must be first. + + while (1) { + + if (wpc->reader->read_bytes (wpc->wv_in, &ChunkHeader, sizeof (ChunkHeader)) != + sizeof (ChunkHeader)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else { + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader)); + wpc->wrapper_bytes += sizeof (ChunkHeader); + } + + little_endian_to_native (&ChunkHeader, ChunkHeaderFormat); + + if (!strncmp (ChunkHeader.ckID, "fmt ", 4)) { + + if (ChunkHeader.ckSize < sizeof (wavhdr) || + wpc->reader->read_bytes (wpc->wv_in, &wavhdr, sizeof (wavhdr)) != sizeof (wavhdr)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr)); + wpc->wrapper_bytes += sizeof (wavhdr); + } + + little_endian_to_native (&wavhdr, WaveHeader3Format); + + if (ChunkHeader.ckSize > sizeof (wavhdr)) { + uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L; + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip); + wpc->wrapper_bytes += bytes_to_skip; + } + else { + uchar *temp = malloc (bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); + free (temp); + } + } + } + else if (!strncmp (ChunkHeader.ckID, "data", 4)) { + wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels / + ((wavhdr.BitsPerSample > 16) ? 3 : 2); + + break; + } + else if ((ChunkHeader.ckSize + 1) & ~1L) { + uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L; + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip); + wpc->wrapper_bytes += bytes_to_skip; + } + else { + uchar *temp = malloc (bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); + free (temp); + } + } + } + } + } + else { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (((char *) &wphdr) [8] == 2 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, 2) != 2)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else if (((char *) &wphdr) [8] == 3 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, + sizeof (wphdr) - 10) != sizeof (wphdr) - 10)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + little_endian_to_native (&wphdr, WavpackHeader3Format); + + // make sure this is a version we know about + + if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + // Because I ran out of flag bits in the WavPack header, an amazingly ugly + // kludge was forced upon me! This code takes care of preparing the flags + // field for internal use and checking for unknown formats we can't decode + + if (wphdr.version == 3) { + + if (wphdr.flags & EXTREME_DECORR) { + + if ((wphdr.flags & NOT_STORED_FLAGS) || + ((wphdr.bits) && + (((wphdr.flags & NEW_HIGH_FLAG) && + (wphdr.flags & (FAST_FLAG | HIGH_FLAG))) || + (wphdr.flags & CROSS_DECORR)))) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wphdr.flags & CANCEL_EXTREME) + wphdr.flags &= ~(EXTREME_DECORR | CANCEL_EXTREME); + } + else + wphdr.flags &= ~CROSS_DECORR; + } + + // check to see if we should look for a "correction" file, and if so try + // to open it for reading, then set WVC_FLAG accordingly + + if (wpc->wvc_in && wphdr.version == 3 && wphdr.bits && (wphdr.flags & NEW_HIGH_FLAG)) { + wpc->file2len = wpc->reader->get_length (wpc->wvc_in); + wphdr.flags |= WVC_FLAG; + wpc->wvc_flag = TRUE; + } + else + wphdr.flags &= ~WVC_FLAG; + + // check WavPack version to handle special requirements of versions + // before 3.0 that had smaller headers + + if (wphdr.version < 3) { + wphdr.total_samples = wpc->total_samples; + wphdr.flags = wavhdr.NumChannels == 1 ? MONO_FLAG : 0; + wphdr.shift = 16 - wavhdr.BitsPerSample; + + if (wphdr.version == 1) + wphdr.bits = 0; + } + + wpc->config.sample_rate = wavhdr.SampleRate; + wpc->config.num_channels = wavhdr.NumChannels; + + if (wphdr.flags & MONO_FLAG) + wpc->config.flags |= CONFIG_MONO_FLAG; + + if (wphdr.flags & EXTREME_DECORR) + wpc->config.flags |= CONFIG_HIGH_FLAG; + + if (wphdr.bits) { + if (wphdr.flags & NEW_HIGH_FLAG) + wpc->config.flags |= CONFIG_HYBRID_FLAG; + else + wpc->config.flags |= CONFIG_LOSSY_MODE; + } + else if (!(wphdr.flags & HIGH_FLAG)) + wpc->config.flags |= CONFIG_FAST_FLAG; + + wpc->config.bytes_per_sample = (wphdr.flags & BYTES_3) ? 3 : 2; + wpc->config.bits_per_sample = wavhdr.BitsPerSample; + + memcpy (&wps->wphdr, &wphdr, sizeof (wphdr)); + wps->wvbits.bufsiz = wps->wvcbits.bufsiz = 1024 * 1024; + return wpc; +} + +// return currently decoded sample index + +uint32_t get_sample_index3 (WavpackContext *wpc) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + return (wps) ? wps->sample_index : (uint32_t) -1; +} + +int get_version3 (WavpackContext *wpc) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + return (wps) ? wps->wphdr.version : 0; +} + +void free_stream3 (WavpackContext *wpc) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + if (wps) { +#ifdef SEEKING + if (wps->unpack_data) + free (wps->unpack_data); +#endif + if (wps->wphdr.flags & WVC_FLAG) + bs_close_read3 (&wps->wvcbits); + + bs_close_read3 (&wps->wvbits); + + free (wps); + } +} + +static void bs_read3 (Bitstream3 *bs) +{ + uint32_t bytes_read; + + bytes_read = bs->reader->read_bytes (bs->id, bs->buf, bs->bufsiz); + bs->end = bs->buf + bytes_read; + bs->fpos += bytes_read; + + if (bs->end == bs->buf) { + memset (bs->buf, -1, bs->bufsiz); + bs->end += bs->bufsiz; + } + + bs->ptr = bs->buf; +} + +// Open the specified BitStream and associate with the specified file. The +// "bufsiz" field of the structure must be preset with the desired buffer +// size and the file's read pointer must be set to where the desired bit +// data is located. A return value of TRUE indicates an error in +// allocating buffer space. + +static int bs_open_read3 (Bitstream3 *bs, stream_reader *reader, void *id) +{ + bs->fpos = (bs->reader = reader)->get_pos (bs->id = id); + + if (!bs->buf) + bs->buf = (uchar *) malloc (bs->bufsiz); + + bs->end = bs->buf + bs->bufsiz; + bs->ptr = bs->end - 1; + bs->sr = bs->bc = 0; + bs->error = bs->buf ? 0 : 1; + bs->wrap = bs_read3; + return bs->error; +} + +#ifdef SEEKING + +// This function is called after a call to unpack_restore() has restored +// the BitStream structure to a previous state and causes any required data +// to be read from the file. This function is NOT supported for overlapped +// operation. + +void bs_restore3 (Bitstream3 *bs) +{ + uint32_t bytes_to_read = bs->end - bs->ptr - 1, bytes_read; + + bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read); + + if (bytes_to_read > 0) { + + bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read); + + if (bytes_to_read != bytes_read) + bs->end = bs->ptr + 1 + bytes_read; + } +} + +#endif + +// This function is called to release any resources used by the BitStream +// and position the file pointer to the first byte past the read bits. + +static void bs_close_read3 (Bitstream3 *bs) +{ + if (bs->buf) { + free (bs->buf); + CLEAR (*bs); + } +} + +static uint32_t bs_unused_bytes (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return bs->end - bs->ptr; +} + +static uchar *bs_unused_data (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return bs->ptr; +} + +#ifdef UNPACK + +//////////////////////////////// local macros ///////////////////////////////// + +#define apply_weight_n(bits, weight, sample) ((weight * sample + (1 << (bits - 1))) >> bits) + +#define update_weight_n(bits, weight, source, result) \ + if (source && result) { \ + if ((source ^ result) >= 0) { if (weight++ == (1 << bits)) weight--; } \ + else if (weight-- == min_weight) weight++; \ + } + +#define apply_weight24(weight, sample) (((((sample & 0xffff) * weight) >> 7) + \ + (((sample & ~0xffff) >> 7) * weight) + 1) >> 1) + +#define update_weight2(weight, source, result) \ + if (source && result) { \ + if ((source ^ result) >= 0) { if (weight++ == 256) weight--; } \ + else if (weight-- == min_weight) weight++; \ + } + +//////////////////////////////// local tables /////////////////////////////// + +// These three tables specify the characteristics of the decorrelation filters. +// Each term represents one layer of the sequential filter, where positive +// values indicate the relative sample involved from the same channel (1=prev) +// while -1 and -2 indicate cross channel decorrelation (in stereo only). The +// "simple_terms" table is no longer used for writing, but is kept for older +// file decoding. + +static const char extreme_terms [] = { 1,1,1,2,4,-1,1,2,3,6,-2,8,5,7,4,1,2,3 }; +static const char default_terms [] = { 1,1,1,-1,2,1,-2 }; +static const char simple_terms [] = { 1,1,1,1 }; + +// This function initializes everything required to unpack WavPack +// bitstreams and must be called before any unpacking is performed. Note +// that the (WavpackHeader3 *) in the WavpackStream3 struct must be valid. + +static void init_words3 (WavpackStream3 *wps); + +static void unpack_init3 (WavpackStream3 *wps) +{ + int flags = wps->wphdr.flags; + struct decorr_pass *dpp; + int ti; + + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + + if (flags & EXTREME_DECORR) { + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (extreme_terms); ti++) + if (extreme_terms [sizeof (extreme_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) + dpp++->term = extreme_terms [sizeof (extreme_terms) - ti - 1]; + } + else if (flags & NEW_DECORR_FLAG) { + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (default_terms); ti++) + if (default_terms [sizeof (default_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) + dpp++->term = default_terms [sizeof (default_terms) - ti - 1]; + } + else + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (simple_terms); ti++) + dpp++->term = simple_terms [sizeof (simple_terms) - ti - 1]; + + wps->num_terms = dpp - wps->decorr_passes; + init_words3 (wps); +} + +#ifdef SEEKING + +#define SAVE(destin, item) { memcpy (destin, &item, sizeof (item)); destin = (char *) destin + sizeof (item); } +#define RESTORE(item, source) { memcpy (&item, source, sizeof (item)); source = (char *) source + sizeof (item); } + +// This function returns the size (in bytes) required to save the unpacking +// context. Note that the (WavpackHeader3 *) in the WavpackStream3 struct +// must be valid. + +static int unpack_size (WavpackStream3 *wps) +{ + int flags = wps->wphdr.flags, byte_sum = 0, tcount; + struct decorr_pass *dpp; + + byte_sum += sizeof (wps->wvbits); + + if (flags & WVC_FLAG) + byte_sum += sizeof (wps->wvcbits); + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) + byte_sum += sizeof (wps->w4); + else + byte_sum += sizeof (wps->w1); + + byte_sum += sizeof (wps->w3) + sizeof (wps->dc.crc); + } + else + byte_sum += sizeof (wps->w2); + + if (wps->wphdr.bits) + byte_sum += sizeof (wps->dc.error); + else + byte_sum += sizeof (wps->dc.sum_level) + sizeof (wps->dc.left_level) + + sizeof (wps->dc.right_level) + sizeof (wps->dc.diff_level); + + if (flags & OVER_20) + byte_sum += sizeof (wps->dc.last_extra_bits) + sizeof (wps->dc.extra_bits_count); + + if (!(flags & EXTREME_DECORR)) { + byte_sum += sizeof (wps->dc.sample); + byte_sum += sizeof (wps->dc.weight); + } + + if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + byte_sum += sizeof (dpp->samples_A [0]) * dpp->term; + byte_sum += sizeof (dpp->weight_A); + + if (!(flags & MONO_FLAG)) { + byte_sum += sizeof (dpp->samples_B [0]) * dpp->term; + byte_sum += sizeof (dpp->weight_B); + } + } + else { + byte_sum += sizeof (dpp->samples_A [0]) + sizeof (dpp->samples_B [0]); + byte_sum += sizeof (dpp->weight_A) + sizeof (dpp->weight_B); + } + + return byte_sum; +} + +// This function saves the unpacking context at the specified pointer and +// returns the updated pointer. The actual amount of data required can be +// determined beforehand by calling unpack_size() but must be allocated by +// the caller. + +static void *unpack_save (WavpackStream3 *wps, void *destin) +{ + int flags = wps->wphdr.flags, tcount; + struct decorr_pass *dpp; + + SAVE (destin, wps->wvbits); + + if (flags & WVC_FLAG) + SAVE (destin, wps->wvcbits); + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) { + SAVE (destin, wps->w4); + } + else { + SAVE (destin, wps->w1); + } + + SAVE (destin, wps->w3); + SAVE (destin, wps->dc.crc); + } + else + SAVE (destin, wps->w2); + + if (wps->wphdr.bits) { + SAVE (destin, wps->dc.error); + } + else { + SAVE (destin, wps->dc.sum_level); + SAVE (destin, wps->dc.left_level); + SAVE (destin, wps->dc.right_level); + SAVE (destin, wps->dc.diff_level); + } + + if (flags & OVER_20) { + SAVE (destin, wps->dc.last_extra_bits); + SAVE (destin, wps->dc.extra_bits_count); + } + + if (!(flags & EXTREME_DECORR)) { + SAVE (destin, wps->dc.sample); + SAVE (destin, wps->dc.weight); + } + + if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int count = dpp->term; + int index = wps->dc.m; + + SAVE (destin, dpp->weight_A); + + while (count--) { + SAVE (destin, dpp->samples_A [index]); + index = (index + 1) & (MAX_TERM - 1); + } + + if (!(flags & MONO_FLAG)) { + count = dpp->term; + index = wps->dc.m; + + SAVE (destin, dpp->weight_B); + + while (count--) { + SAVE (destin, dpp->samples_B [index]); + index = (index + 1) & (MAX_TERM - 1); + } + } + } + else { + SAVE (destin, dpp->weight_A); + SAVE (destin, dpp->weight_B); + SAVE (destin, dpp->samples_A [0]); + SAVE (destin, dpp->samples_B [0]); + } + + return destin; +} + +// This function restores the unpacking context from the specified pointer +// and returns the updated pointer. After this call, unpack_samples() will +// continue where it left off immediately before unpack_save() was called. +// If the WavPack files and bitstreams might have been closed and reopened, +// then the "keep_resources" flag should be set to avoid using the "old" +// resources that were originally saved (and are probably now invalid). + +static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources) +{ + int flags = wps->wphdr.flags, tcount; + struct decorr_pass *dpp; + FILE *temp_file; + uchar *temp_buf; + + unpack_init3 (wps); + temp_file = wps->wvbits.id; + temp_buf = wps->wvbits.buf; + RESTORE (wps->wvbits, source); + + if (keep_resources) { + wps->wvbits.id = temp_file; + wps->wvbits.ptr += temp_buf - wps->wvbits.buf; + wps->wvbits.end += temp_buf - wps->wvbits.buf; + wps->wvbits.buf = temp_buf; + } + + bs_restore3 (&wps->wvbits); + + if (flags & WVC_FLAG) { + temp_file = wps->wvcbits.id; + temp_buf = wps->wvcbits.buf; + RESTORE (wps->wvcbits, source); + + if (keep_resources) { + wps->wvcbits.id = temp_file; + wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf; + wps->wvcbits.end += temp_buf - wps->wvcbits.buf; + wps->wvcbits.buf = temp_buf; + } + + bs_restore3 (&wps->wvcbits); + } + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) { + RESTORE (wps->w4, source); + } + else { + RESTORE (wps->w1, source); + } + + RESTORE (wps->w3, source); + RESTORE (wps->dc.crc, source); + } + else + RESTORE (wps->w2, source); + + if (wps->wphdr.bits) { + RESTORE (wps->dc.error, source); + } + else { + RESTORE (wps->dc.sum_level, source); + RESTORE (wps->dc.left_level, source); + RESTORE (wps->dc.right_level, source); + RESTORE (wps->dc.diff_level, source); + } + + if (flags & OVER_20) { + RESTORE (wps->dc.last_extra_bits, source); + RESTORE (wps->dc.extra_bits_count, source); + } + + if (!(flags & EXTREME_DECORR)) { + RESTORE (wps->dc.sample, source); + RESTORE (wps->dc.weight, source); + } + + if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int count = dpp->term; + int index = wps->dc.m; + + RESTORE (dpp->weight_A, source); + + while (count--) { + RESTORE (dpp->samples_A [index], source); + index = (index + 1) & (MAX_TERM - 1); + } + + if (!(flags & MONO_FLAG)) { + count = dpp->term; + index = wps->dc.m; + + RESTORE (dpp->weight_B, source); + + while (count--) { + RESTORE (dpp->samples_B [index], source); + index = (index + 1) & (MAX_TERM - 1); + } + } + } + else { + RESTORE (dpp->weight_A, source); + RESTORE (dpp->weight_B, source); + RESTORE (dpp->samples_A [0], source); + RESTORE (dpp->samples_B [0], source); + } + + return source; +} + +// This is an extension for WavpackSeekSample (). Note that because WavPack +// files created prior to version 4.0 are not inherently seekable, this +// function could take a long time if a forward seek is requested to an +// area that has not been played (or seeked through) yet. + + +int seek_sample3 (WavpackContext *wpc, uint32_t desired_index) +{ + int points_index = desired_index / ((wpc->total_samples >> 8) + 1); + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + if (desired_index >= wpc->total_samples) + return FALSE; + + while (points_index) + if (wps->index_points [points_index].saved && + wps->index_points [points_index].sample_index <= desired_index) + break; + else + points_index--; + + if (wps->index_points [points_index].saved) + if (wps->index_points [points_index].sample_index > wps->sample_index || + wps->sample_index > desired_index) { + wps->sample_index = wps->index_points [points_index].sample_index; + unpack_restore (wps, wps->unpack_data + points_index * wps->unpack_size, TRUE); + } + + if (desired_index > wps->sample_index) { + int32_t *buffer = (int32_t *) malloc (1024 * (wps->wphdr.flags & MONO_FLAG ? 4 : 8)); + uint32_t samples_to_skip = desired_index - wps->sample_index; + + while (1) { + if (samples_to_skip > 1024) { + if (unpack_samples3 (wpc, buffer, 1024) == 1024) + samples_to_skip -= 1024; + else + break; + } + else { + samples_to_skip -= unpack_samples3 (wpc, buffer, samples_to_skip); + break; + } + } + + free (buffer); + + if (samples_to_skip) + return FALSE; + } + + return TRUE; +} + + +#endif + +// This monster actually unpacks the WavPack bitstream(s) into the specified +// buffer as longs, and serves as an extension to WavpackUnpackSamples(). +// Note that WavPack files created prior to version 4.0 could only contain 16 +// or 24 bit values, and these values are right-justified in the 32-bit values. +// So, if the original file contained 16-bit values, then the range of the +// returned longs would be +/- 32K. For maximum clarity, the function is +// broken up into segments that handle various modes. This makes for a few +// extra infrequent flag checks, but makes the code easier to follow because +// the nesting does not become so deep. For maximum efficiency, the conversion +// is isolated to tight loops that handle an entire buffer. + +static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction); + +int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + int shift = wps->wphdr.shift, flags = wps->wphdr.flags, min_weight = 0, m = wps->dc.m, tcount; +#ifdef SEEKING + int points_index = wps->sample_index / ((wpc->total_samples >> 8) + 1); +#endif + int32_t min_value, max_value, min_shifted, max_shifted; + int32_t correction [2], crc = wps->dc.crc; + struct decorr_pass *dpp; + int32_t read_word, *bptr; + int32_t sample [2] [2]; + int weight [2] [1]; + uint i; + + if (wps->sample_index + sample_count > wpc->total_samples) + sample_count = wpc->total_samples - wps->sample_index; + + if (!sample_count) + return 0; + + if (!wps->sample_index) { + unpack_init3 (wps); + + bs_open_read3 (&wps->wvbits, wpc->reader, wpc->wv_in); + + if (wpc->wvc_flag) + bs_open_read3 (&wps->wvcbits, wpc->reader, wpc->wvc_in); + } + +#ifdef SEEKING + if (!wps->index_points [points_index].saved) { + + if (!wps->unpack_data) + wps->unpack_data = (uchar *) malloc (256 * (wps->unpack_size = unpack_size (wps))); + + wps->index_points [points_index].sample_index = wps->sample_index; + unpack_save (wps, wps->unpack_data + points_index * wps->unpack_size); + wps->index_points [points_index].saved = TRUE; + } +#endif + + memcpy (sample, wps->dc.sample, sizeof (sample)); + memcpy (weight, wps->dc.weight, sizeof (weight)); + + if (wps->wphdr.bits) { + if (flags & (NEW_DECORR_FLAG | EXTREME_DECORR)) + min_weight = -256; + } + else + if (flags & NEW_DECORR_FLAG) + min_weight = (flags & EXTREME_DECORR) ? -512 : -256; + + if (flags & BYTES_3) { + min_shifted = (min_value = -8388608 >> shift) << shift; + max_shifted = (max_value = 8388607 >> shift) << shift; + } + else { + min_shifted = (min_value = -32768 >> shift) << shift; + max_shifted = (max_value = 32767 >> shift) << shift; + } + + ///////////////// handle version 3 lossless mono data ///////////////////// + + if (wps->wphdr.version == 3 && !wps->wphdr.bits && (flags & MONO_FLAG)) { + if (flags & FAST_FLAG) { + if (flags & OVER_20) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + sample [0] [0] += sample [0] [1] += read_word; + getbits (&temp, 4, &wps->wvbits); + crc = crc * 3 + (temp = (temp & 0xf) + (sample [0] [0] << 4)); + *bptr++ = temp; + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + *bptr++ = sample [0] [0] << shift; + } + } + else if (flags & HIGH_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + if (flags & NEW_HIGH_FLAG) { + if ((read_word = get_word1 (wps, 0)) == WORD_EOF) + break; + } + else { + if ((read_word = get_old_word1 (wps, 0)) == WORD_EOF) + break; + } + + if (flags & EXTREME_DECORR) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight_n (9, dpp->weight_A, sam) + read_word; + update_weight_n (9, dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight_n (8, dpp->weight_A, sam) + read_word; + update_weight_n (8, dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&temp, 4, &wps->wvbits); + + if ((temp &= 0xf) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = temp; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (temp = wps->dc.last_extra_bits + (read_word << 4)); + *bptr++ = temp; + } + else { + crc = crc * 3 + read_word; + *bptr++ = read_word << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + int32_t temp; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + temp = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [0] += (sample [0] [1] = temp - sample [0] [0]); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&temp, 4, &wps->wvbits); + + if ((temp &= 0xf) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = temp; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = temp = wps->dc.last_extra_bits + (sample [0] [0] << 4)); + } + else { + crc = crc * 3 + sample [0] [0]; + *bptr++ = sample [0] [0] << shift; + } + } + } + + //////////////// handle version 3 lossless stereo data //////////////////// + + else if (wps->wphdr.version == 3 && !wps->wphdr.bits && !(flags & MONO_FLAG)) { + int32_t left_level = wps->dc.left_level, right_level = wps->dc.right_level; + int32_t sum_level = wps->dc.sum_level, diff_level = wps->dc.diff_level; + + if (flags & FAST_FLAG) { + if (flags & OVER_20) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff, temp; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); + sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); + sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); + getbits (&temp, 8, &wps->wvbits); + crc = crc * 3 + (*bptr++ = (sample [0] [0] << 4) + ((temp >> 4) & 0xf)); + crc = crc * 3 + (*bptr++ = (sample [1] [0] << 4) + (temp & 0xf)); + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); + sample [0] [1] += ((sum + diff) >> 1); + sample [1] [1] += ((sum - diff) >> 1); + crc = crc * 3 + (sample [0] [0] += sample [0] [1]); + crc = crc * 3 + (sample [1] [0] += sample [1] [1]); + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + } + else if (flags & HIGH_FLAG) { + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, left, right, diff, left2, right2, extra_bits, next_word; + + if (flags & CROSS_DECORR) { + left = get_word1 (wps, 0); + + if (left == WORD_EOF) + break; + + right = get_word1 (wps, 1); + } + else { + if (flags & NEW_HIGH_FLAG) { + read_word = get_word1 (wps, 0); + + if (read_word == WORD_EOF) + break; + + next_word = get_word1 (wps, 1); + + if (right_level > left_level) { + if (left_level + right_level < sum_level + diff_level && right_level < diff_level) { + sum = (right = read_word) + (left = next_word); + diff = left - right; + } + else { + diff = read_word; + + if (sum_level < left_level) { + sum = (next_word << 1) | (diff & 1); + left = (sum + diff) >> 1; + right = (sum - diff) >> 1; + } + else + sum = left + (right = (left = next_word) - diff); + } + } + else { + if (left_level + right_level < sum_level + diff_level && left_level < diff_level) { + sum = (left = read_word) + (right = next_word); + diff = left - right; + } + else { + diff = read_word; + + if (sum_level < right_level) { + sum = (next_word << 1) | (diff & 1); + left = (sum + diff) >> 1; + right = (sum - diff) >> 1; + } + else + sum = (left = diff + (right = next_word)) + right; + } + } + } + else { + read_word = get_old_word1 (wps, 0); + + if (read_word == WORD_EOF) + break; + + next_word = get_old_word1 (wps, 1); + + if (sum_level <= right_level && sum_level <= left_level) { + sum = (next_word << 1) | (read_word & 1); + left = (sum + read_word) >> 1; + right = (sum - read_word) >> 1; + } + else if (left_level <= right_level) + sum = left + (right = (left = next_word) - read_word); + else + sum = right + (left = read_word + (right = next_word)); + + diff = left - right; + } + + sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); + left_level = left_level - (left_level >> 8) + labs (left); + right_level = right_level - (right_level >> 8) + labs (right); + diff_level = diff_level - (diff_level >> 8) + labs (diff); + + if (flags & JOINT_STEREO) { + left = diff; + right = sum >> 1; + } + } + + if (flags & EXTREME_DECORR) { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight_n (9, dpp->weight_A, sam_A) + left; + right2 = apply_weight_n (9, dpp->weight_B, sam_B) + right; + + update_weight_n (9, dpp->weight_A, sam_A, left); + update_weight_n (9, dpp->weight_B, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (9, dpp->weight_A, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight_n (9, dpp->weight_B, left); + update_weight_n (9, dpp->weight_B, left, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (9, dpp->weight_A, dpp->samples_A [0], right); + right = right2; + left2 = left + apply_weight_n (9, dpp->weight_B, right); + update_weight_n (9, dpp->weight_B, right, left); + dpp->samples_A [0] = left = left2; + } + } + else { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight_n (8, dpp->weight_A, sam_A) + left; + right2 = apply_weight_n (8, dpp->weight_B, sam_B) + right; + + update_weight_n (8, dpp->weight_A, sam_A, left); + update_weight_n (8, dpp->weight_B, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (8, dpp->weight_A, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight_n (8, dpp->weight_B, left); + update_weight_n (8, dpp->weight_B, left, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (8, dpp->weight_A, dpp->samples_A [0], right); + right = right2; + left2 = left + apply_weight_n (8, dpp->weight_B, right); + update_weight_n (8, dpp->weight_B, right, left); + dpp->samples_A [0] = left = left2; + } + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & JOINT_STEREO) { + sum = (right << 1) | ((diff = left) & 1); + right = (sum - diff) >> 1; + left = (sum + diff) >> 1; + } + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&extra_bits, 8, &wps->wvbits); + + if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = extra_bits; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = left = (left << 4) + (wps->dc.last_extra_bits >> 4)); + crc = crc * 3 + (*bptr++ = right = (right << 4) + (wps->dc.last_extra_bits & 0xf)); + } + else { + crc = crc * 9 + left * 3 + right; + *bptr++ = left << shift; + *bptr++ = right << shift; + } + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, left, right, left2, right2, extra_bits; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + if (sum_level <= right_level && sum_level <= left_level) { + sum = (get_word3 (wps, 1) << 1) | (read_word & 1); + left = (sum + read_word) >> 1; + right = (sum - read_word) >> 1; + } + else if (left_level <= right_level) + sum = left + (right = (left = get_word3 (wps, 1)) - read_word); + else + sum = right + (left = read_word + (right = get_word3 (wps, 1))); + + sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); + left_level = left_level - (left_level >> 8) + labs (left); + right_level = right_level - (right_level >> 8) + labs (right); + + left2 = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + left; + right2 = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + right; + + if ((sample [0] [1] >= 0) == (left > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + if ((sample [1] [1] >= 0) == (right > 0)) { + if (weight [1] [0]++ == 256) + weight [1] [0]--; + } + else if (weight [1] [0]-- == 0) + weight [1] [0]++; + + sample [0] [0] += (sample [0] [1] = left2 - sample [0] [0]); + sample [1] [0] += (sample [1] [1] = right2 - sample [1] [0]); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&extra_bits, 8, &wps->wvbits); + + if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = extra_bits; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = left2 = (sample [0] [0] << 4) + (wps->dc.last_extra_bits >> 4)); + crc = crc * 3 + (*bptr++ = right2 = (sample [1] [0] << 4) + (wps->dc.last_extra_bits & 0xf)); + } + else { + crc = crc * 9 + sample [0] [0] * 3 + sample [1] [0]; + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + } + + wps->dc.left_level = left_level; + wps->dc.right_level = right_level; + wps->dc.sum_level = sum_level; + wps->dc.diff_level = diff_level; + } + + //////////////// handle version 3 lossy/hybrid mono data ////////////////// + + else if (wps->wphdr.version == 3 && wps->wphdr.bits && (flags & MONO_FLAG)) { + if (flags & FAST_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + } + else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + read_word = (flags & NEW_HIGH_FLAG) ? + get_word4 (wps, 0, correction) : get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight24 (dpp->weight_A, sam) + read_word; + update_weight2 (dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & WVC_FLAG) { + if (flags & LOSSY_SHAPE) { + crc = crc * 3 + (read_word += correction [0] + wps->dc.error [0]); + wps->dc.error [0] = -correction [0]; + } + else + crc = crc * 3 + (read_word += correction [0]); + + *bptr++ = read_word << shift; + } + else { + crc = crc * 3 + read_word; + + if (read_word < min_value) + *bptr++ = min_shifted; + else if (read_word > max_value) + *bptr++ = max_shifted; + else + *bptr++ = read_word << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t new_sample; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [1] = new_sample - sample [0] [0]; + crc = crc * 3 + (sample [0] [0] = new_sample); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + } + } + + //////////////// handle version 3 lossy/hybrid stereo data //////////////// + + else if (wps->wphdr.version == 3 && wps->wphdr.bits && !(flags & MONO_FLAG)) { + if (flags & FAST_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + + crc = crc * 3 + (sample [1] [0] += sample [1] [1] += get_word3 (wps, 1)); + + if (sample [1] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [1] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [1] [0] << shift; + } + else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, left2, right2, sum, diff; + + if (flags & NEW_HIGH_FLAG) { + left = get_word4 (wps, 0, correction); + right = get_word4 (wps, 1, correction + 1); + } + else { + left = get_word3 (wps, 0); + right = get_word3 (wps, 1); + } + + if (left == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight24 (dpp->weight_A, sam_A) + left; + update_weight2 (dpp->weight_A, sam_A, left); + dpp->samples_A [k] = left = left2; + + right2 = apply_weight24 (dpp->weight_B, sam_B) + right; + update_weight2 (dpp->weight_B, sam_B, right); + dpp->samples_B [k] = right = right2; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & WVC_FLAG) { + if (flags & LOSSY_SHAPE) { + left += correction [0] + wps->dc.error [0]; + right += correction [1] + wps->dc.error [1]; + wps->dc.error [0] = -correction [0]; + wps->dc.error [1] = -correction [1]; + } + else { + left += correction [0]; + right += correction [1]; + } + } + + if (flags & JOINT_STEREO) { + right = ((sum = (right << 1) | (left & 1)) - (diff = left)) >> 1; + left = (sum + diff) >> 1; + } + + crc = crc * 9 + left * 3 + right; + + if (flags & WVC_FLAG) { + *bptr++ = left << shift; + *bptr++ = right << shift; + } + else { + if (left < min_value) + *bptr++ = min_shifted; + else if (left > max_value) + *bptr++ = max_shifted; + else + *bptr++ = left << shift; + + if (right < min_value) + *bptr++ = min_shifted; + else if (right > max_value) + *bptr++ = max_shifted; + else + *bptr++ = right << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t new_sample; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [1] = new_sample - sample [0] [0]; + crc = crc * 3 + (sample [0] [0] = new_sample); + + read_word = get_word3 (wps, 1); + new_sample = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + read_word; + + if ((sample [1] [1] >= 0) == (read_word > 0)) { + if (weight [1] [0]++ == 256) + weight [1] [0]--; + } + else if (weight [1] [0]-- == 0) + weight [1] [0]++; + + sample [1] [1] = new_sample - sample [1] [0]; + crc = crc * 3 + (sample [1] [0] = new_sample); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + + if (sample [1] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [1] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [1] [0] << shift; + } + } + + //////////////////// finally, handle version 2 data /////////////////////// + + else if (wps->wphdr.version == 2 && (flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word2 (wps, 0)) == WORD_EOF) + break; + + sample [0] [0] += sample [0] [1] += read_word; + + if (wps->wphdr.bits) { + if (sample [0] [0] < min_value) + sample [0] [0] = min_value; + else if (sample [0] [0] > max_value) + sample [0] [0] = max_value; + } + + *bptr++ = sample [0] [0] << shift; + } + else if (wps->wphdr.version < 3 && !(flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff; + + read_word = get_word2 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word2 (wps, 1)) & 1); + sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); + sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); + + if (wps->wphdr.bits) { + if (sample [0] [0] < min_value) + sample [0] [0] = min_value; + else if (sample [0] [0] > max_value) + sample [0] [0] = max_value; + + if (sample [1] [0] < min_value) + sample [1] [0] = min_value; + else if (sample [1] [0] > max_value) + sample [1] [0] = max_value; + } + + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + + if (i && (wps->sample_index += i) == wpc->total_samples) { + + if (wps->wphdr.version == 3 && crc != (wpc->wvc_flag ? wps->wphdr.crc2 : wps->wphdr.crc)) + wpc->crc_errors++; + + if (wpc->open_flags & OPEN_WRAPPER) { + uchar *temp = malloc (1024); + uint32_t bcount; + + if (bs_unused_bytes (&wps->wvbits)) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bs_unused_bytes (&wps->wvbits)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, bs_unused_data (&wps->wvbits), bs_unused_bytes (&wps->wvbits)); + wpc->wrapper_bytes += bs_unused_bytes (&wps->wvbits); + } + + while (1) { + bcount = wpc->reader->read_bytes (wpc->wv_in, temp, sizeof (temp)); + + if (!bcount) + break; + + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bcount); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, temp, bcount); + wpc->wrapper_bytes += bcount; + } + + free (temp); + + if (wpc->wrapper_bytes > 16) { + int c; + + for (c = 0; c < 16 && wpc->wrapper_data [c] == 0xff; ++c); + + if (c == 16) { + memcpy (wpc->wrapper_data, wpc->wrapper_data + 16, wpc->wrapper_bytes - 16); + wpc->wrapper_bytes -= 16; + } + else { + free (wpc->wrapper_data); + wpc->wrapper_data = NULL; + wpc->wrapper_bytes = 0; + } + } + } + } + + memcpy (wps->dc.sample, sample, sizeof (sample)); + memcpy (wps->dc.weight, weight, sizeof (weight)); + wps->dc.crc = crc; + wps->dc.m = m; + + return i; +} + +///////////////////////////// local table storage //////////////////////////// + +extern const uint32_t bitset []; +extern const uint32_t bitmask []; +extern const char nbits_table []; + +// This function initializes everything required to receive words with this +// module and must be called BEFORE any other function in this module. + +static void init_words3 (WavpackStream3 *wps) +{ + CLEAR (wps->w1); + CLEAR (wps->w2); + CLEAR (wps->w3); + CLEAR (wps->w4); + + if (wps->wphdr.flags & MONO_FLAG) + wps->w4.bitrate = wps->wphdr.bits - 768; + else + wps->w4.bitrate = (wps->wphdr.bits / 2) - 768; +} + +// This macro counts the number of bits that are required to specify the +// unsigned 32-bit value, counting from the LSB to the most significant bit +// that is set. Return range is 0 - 32. + +#define count_bits(av) ( \ + (av) < (1 << 8) ? nbits_table [av] : \ + ( \ + (av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \ + ((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \ + ) \ +) + +static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan) +{ + uint32_t tmp1, tmp2, avalue; + uint ones_count; + int k; + + if ((wps->wphdr.flags & EXTREME_DECORR) && !(wps->wphdr.flags & OVER_20)) { + if (wps->w1.zeros_acc) { + if (--wps->w1.zeros_acc) + return 0; + } + else if (wps->w1.ave_level [0] [0] < 0x20 && wps->w1.ave_level [0] [1] < 0x20) { + int32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + wps->w1.zeros_acc = cbits; + else { + for (mask = 1, wps->w1.zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + wps->w1.zeros_acc |= mask; + + wps->w1.zeros_acc |= mask; + } + + if (wps->w1.zeros_acc) + return 0; + } + } + + // count consecutive ones in bitstream, > 25 indicates error (or EOF) + + for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == 25) + return WORD_EOF; + + k = (wps->w1.ave_level [0] [chan] + (wps->w1.ave_level [0] [chan] >> 3) + 0x40) >> 7; + k = count_bits (k); + + if (ones_count == 0) { + getbits (&avalue, k, &wps->wvbits); + avalue &= bitmask [k]; + } + else { + tmp1 = bitset [k]; + k = (wps->w1.ave_level [1] [chan] + (wps->w1.ave_level [1] [chan] >> 4) + 0x20) >> 6; + k = count_bits (k); + + if (ones_count == 1) { + getbits (&avalue, k, &wps->wvbits); + avalue &= bitmask [k]; + } + else { + tmp2 = bitset [k]; + + // If the ones count is exactly 24, then next 24 bits are literal + + if (ones_count == 24) { + getbits (&avalue, 24, &wps->wvbits); + avalue &= 0xffffff; + } + else { + k = (wps->w1.ave_level [2] [chan] + 0x10) >> 5; + k = count_bits (k); + getbits (&avalue, k, &wps->wvbits); + avalue = (avalue & bitmask [k]) + (bitset [k] * (ones_count - 2)); + } + + wps->w1.ave_level [2] [chan] -= ((wps->w1.ave_level [2] [chan] + 0x8) >> 4); + wps->w1.ave_level [2] [chan] += avalue; + avalue += tmp2; + } + + wps->w1.ave_level [1] [chan] -= ((wps->w1.ave_level [1] [chan] + 0x10) >> 5); + wps->w1.ave_level [1] [chan] += avalue; + avalue += tmp1; + } + + wps->w1.ave_level [0] [chan] -= ((wps->w1.ave_level [0] [chan] + 0x20) >> 6); + wps->w1.ave_level [0] [chan] += avalue; + + return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; +} + +#define NUM_SAMPLES 128 + +static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan) +{ + uint32_t avalue; + uint bc; + int k; + + if (!wps->w1.index [chan]) { + + int guess_k = (wps->w1.ave_k [chan] + 128) >> 8, ones; + + for (ones = 0; ones < 72 && getbit (&wps->wvbits); ++ones); + + if (ones == 72) + return WORD_EOF; + + if (ones % 3 == 1) + wps->w1.k_value [chan] = guess_k - (ones / 3) - 1; + else + wps->w1.k_value [chan] = guess_k + ones - ((ones + 1) / 3); + + wps->w1.ave_k [chan] -= (wps->w1.ave_k [chan] + 0x10) >> 5; + wps->w1.ave_k [chan] += wps->w1.k_value [chan] << 3; + } + + if (++wps->w1.index [chan] == NUM_SAMPLES) + wps->w1.index [chan] = 0; + + k = wps->w1.k_value [chan]; + getbits (&avalue, k, &wps->wvbits); + + for (bc = 0; bc < 32 && getbit (&wps->wvbits); ++bc); + + if (bc == 32) + return WORD_EOF; + + avalue = (avalue & bitmask [k]) + bitset [k] * bc; + return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; +} + +static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan) +{ + int cbits, delta_dbits, dbits; + int32_t value, mask = 1; + + cbits = 0; + + while (getbit (&wps->wvbits)) + if ((cbits += 2) == 50) + return WORD_EOF; + + if (getbit (&wps->wvbits)) + cbits++; + + if (cbits == 0) + delta_dbits = 0; + else if (cbits & 1) { + delta_dbits = (cbits + 1) / 2; + + if (wps->w2.last_delta_sign [chan] > 0) + delta_dbits *= -1; + + wps->w2.last_delta_sign [chan] = delta_dbits; + } + else { + delta_dbits = cbits / 2; + + if (wps->w2.last_delta_sign [chan] <= 0) + delta_dbits *= -1; + } + + dbits = (wps->w2.last_dbits [chan] += delta_dbits); + + if (dbits < 0 || dbits > 20) + return WORD_EOF; + + if (!dbits) + return 0L; + + if (wps->wphdr.bits) { + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) + if (dbits < wps->wphdr.bits && getbit (&wps->wvbits)) + value |= mask; + } + else + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) + if (getbit (&wps->wvbits)) + value |= mask; + + return getbit (&wps->wvbits) ? -(int32_t)value : value; +} + +static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan) +{ + int cbits, delta_dbits, dbits; + int32_t value; + + for (cbits = 0; cbits < 72 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 72) + return WORD_EOF; + + if (cbits || getbit (&wps->wvbits)) + ++cbits; + + if (!((cbits + 1) % 3)) + delta_dbits = (cbits + 1) / 3; + else + delta_dbits = -(cbits - cbits / 3); + + if (chan) { + dbits = (wps->w3.ave_dbits [1] >> 8) + 1 + delta_dbits; + wps->w3.ave_dbits [1] -= (wps->w3.ave_dbits [1] + 0x10) >> 5; + wps->w3.ave_dbits [1] += dbits << 3; + } + else { + dbits = (wps->w3.ave_dbits [0] >> 8) + 1 + delta_dbits; + wps->w3.ave_dbits [0] -= (wps->w3.ave_dbits [0] + 0x10) >> 5; + wps->w3.ave_dbits [0] += dbits << 3; + } + + if (dbits < 0 || dbits > 24) + return WORD_EOF; + + if (!dbits) + return 0L; + + if (wps->wphdr.bits && dbits > wps->wphdr.bits) { + getbits (&value, wps->wphdr.bits, &wps->wvbits); + + if (value & bitset [wps->wphdr.bits - 1]) + return -(int32_t)(value & bitmask [wps->wphdr.bits]) << (dbits - wps->wphdr.bits); + else + return ((value & bitmask [wps->wphdr.bits - 1]) | bitset [wps->wphdr.bits - 1]) << (dbits - wps->wphdr.bits); + } + else { + getbits (&value, dbits, &wps->wvbits); + + if (value & bitset [dbits - 1]) + return -(int32_t)(value & bitmask [dbits]); + else + return (value & bitmask [dbits - 1]) | bitset [dbits - 1]; + } +} + +static int FASTCALL _log2 (uint32_t avalue); + +static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction) +{ + uint32_t base, ones_count, avalue; + int32_t value, low, mid, high; + int bitcount; + + // count consecutive ones in bitstream, > 25 indicates error (or EOF) + + for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == 25) + return WORD_EOF; + + // if the ones count is exactly 24, then we switch to non-unary method + + if (ones_count == 24) { + int32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += 24; + } + + if (!chan) { + int slow_log_0, slow_log_1, balance; + + if (wps->wphdr.flags & MONO_FLAG) { + wps->w4.bits_acc [0] += wps->w4.bitrate + _log2 (wps->w4.fast_level [0]) - _log2 (wps->w4.slow_level [0]) + (3 << 8); + + if (wps->w4.bits_acc [0] < 0) + wps->w4.bits_acc [0] = 0; + } + else { + slow_log_0 = _log2 (wps->w4.slow_level [0]); + slow_log_1 = _log2 (wps->w4.slow_level [1]); + + if (wps->wphdr.flags & JOINT_STEREO) + balance = (slow_log_1 - slow_log_0 + 257) >> 1; + else + balance = (slow_log_1 - slow_log_0 + 1) >> 1; + + wps->w4.bits_acc [0] += wps->w4.bitrate - balance + _log2 (wps->w4.fast_level [0]) - slow_log_0 + (3 << 8); + wps->w4.bits_acc [1] += wps->w4.bitrate + balance + _log2 (wps->w4.fast_level [1]) - slow_log_1 + (3 << 8); + + if (wps->w4.bits_acc [0] + wps->w4.bits_acc [1] < 0) + wps->w4.bits_acc [0] = wps->w4.bits_acc [1] = 0; + else if (wps->w4.bits_acc [0] < 0) { + wps->w4.bits_acc [1] += wps->w4.bits_acc [0]; + wps->w4.bits_acc [0] = 0; + } + else if (wps->w4.bits_acc [1] < 0) { + wps->w4.bits_acc [0] += wps->w4.bits_acc [1]; + wps->w4.bits_acc [1] = 0; + } + } + } + + base = (wps->w4.fast_level [chan] + 48) / 96; + bitcount = wps->w4.bits_acc [chan] >> 8; + wps->w4.bits_acc [chan] &= 0xff; + + if (!base) { + if (ones_count) + high = low = mid = (getbit (&wps->wvbits)) ? -(int32_t)ones_count : ones_count; + else + high = low = mid = 0; + } + else { + mid = (ones_count * 2 + 1) * base; + if (getbit (&wps->wvbits)) mid = -mid; + low = mid - base; + high = mid + base - 1; + + while (bitcount--) { + if (getbit (&wps->wvbits)) + mid = (high + (low = mid) + 1) >> 1; + else + mid = ((high = mid - 1) + low + 1) >> 1; + + if (high == low) + break; + } + } + + wps->w4.fast_level [chan] -= ((wps->w4.fast_level [chan] + 0x10) >> 5); + wps->w4.fast_level [chan] += (avalue = labs (mid)); + wps->w4.slow_level [chan] -= ((wps->w4.slow_level [chan] + 0x80) >> 8); + wps->w4.slow_level [chan] += avalue; + + if (bs_is_open (&wps->wvcbits)) { + + if (high != low) { + uint32_t maxcode = high - low; + int bitcount = count_bits (maxcode); + uint32_t extras = (1L << bitcount) - maxcode - 1; + + getbits (&avalue, bitcount - 1, &wps->wvcbits); + avalue &= bitmask [bitcount - 1]; + + if (avalue >= extras) { + avalue = (avalue << 1) - extras; + + if (getbit (&wps->wvcbits)) + ++avalue; + } + + value = (mid < 0) ? high - avalue : avalue + low; + + if (correction) + *correction = value - mid; + } + else if (correction) + *correction = 0; + } + + return mid; +} + +// This function calculates an approximate base-2 logarithm (with 8 bits of +// fraction) from the supplied value. Using logarithms makes comparing +// signal level values and calculating fractional bitrates much easier. + +static int FASTCALL _log2 (uint32_t avalue) +{ + int dbits; + + if ((avalue += avalue >> 9) < (1 << 8)) { + dbits = nbits_table [avalue]; + return (dbits << 8) + ((avalue << (9 - dbits)) & 0xff); + } + else { + if (avalue < (1L << 16)) + dbits = nbits_table [avalue >> 8] + 8; + else if (avalue < (1L << 24)) + dbits = nbits_table [avalue >> 16] + 16; + else + dbits = nbits_table [avalue >> 24] + 24; + + return (dbits << 8) + ((avalue >> (dbits - 9)) & 0xff); + } +} + +#endif diff --git a/Libraries/WavPack/Files/unpack3.h b/Libraries/WavPack/Files/unpack3.h new file mode 100644 index 000000000..d958141b4 --- /dev/null +++ b/Libraries/WavPack/Files/unpack3.h @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wavpack3.h + +// This header file contains all the additional definitions required for +// decoding old (versions 1, 2 & 3) WavPack files. + +typedef struct { + ushort FormatTag, NumChannels; + uint32_t SampleRate, BytesPerSecond; + ushort BlockAlign, BitsPerSample; +} WaveHeader3; + +#define WaveHeader3Format "SSLLSS" + +typedef struct { + char ckID [4]; + int32_t ckSize; + short version; + short bits; // added for version 2.00 + short flags, shift; // added for version 3.00 + int32_t total_samples, crc, crc2; + char extension [4], extra_bc, extras [3]; +} WavpackHeader3; + +#define WavpackHeader3Format "4LSSSSLLL4L" + +// these flags added for version 3 + +#undef MONO_FLAG // these definitions changed for WavPack 4.0 +#undef CROSS_DECORR +#undef JOINT_STEREO + +#define MONO_FLAG 1 // not stereo +#define FAST_FLAG 2 // non-adaptive predictor and stereo mode +#define RAW_FLAG 4 // raw mode (no .wav header) +#define CALC_NOISE 8 // calc noise in lossy mode (no longer stored) +#define HIGH_FLAG 0x10 // high quality mode (all modes) +#define BYTES_3 0x20 // files have 3-byte samples +#define OVER_20 0x40 // samples are over 20 bits +#define WVC_FLAG 0x80 // create/use .wvc (no longer stored) +#define LOSSY_SHAPE 0x100 // noise shape (lossy mode only) +#define VERY_FAST_FLAG 0x200 // double fast (no longer stored) +#define NEW_HIGH_FLAG 0x400 // new high quality mode (lossless only) +#define CANCEL_EXTREME 0x800 // cancel EXTREME_DECORR +#define CROSS_DECORR 0x1000 // decorrelate chans (with EXTREME_DECORR flag) +#define NEW_DECORR_FLAG 0x2000 // new high-mode decorrelator +#define JOINT_STEREO 0x4000 // joint stereo (lossy and high lossless) +#define EXTREME_DECORR 0x8000 // extra decorrelation (+ enables other flags) + +#define STORED_FLAGS 0xfd77 // these are only flags that affect unpacking +#define NOT_STORED_FLAGS (~STORED_FLAGS & 0xffff) + +// BitStream stuff (bits.c) + +typedef struct bs3 { + void (*wrap)(struct bs3 *bs); + uchar *buf, *end, *ptr; + uint32_t bufsiz, fpos, sr; + stream_reader *reader; + int error, bc; + void *id; +} Bitstream3; + +#define K_DEPTH 3 +#define MAX_NTERMS3 18 + +typedef struct { + WavpackHeader3 wphdr; + Bitstream3 wvbits, wvcbits; + uint32_t sample_index; + int num_terms; + +#ifdef SEEKING + struct index_point { + char saved; + uint32_t sample_index; + } index_points [256]; + + uchar *unpack_data; + uint32_t unpack_size; +#endif + + struct { + int32_t sum_level, left_level, right_level, diff_level; + int last_extra_bits, extra_bits_count, m; + int32_t error [2], crc; + int32_t sample [2] [2]; + int weight [2] [1]; + } dc; + + struct decorr_pass decorr_passes [MAX_NTERMS3]; + + struct { + uint index [2], k_value [2], ave_k [2]; + uint32_t zeros_acc, ave_level [K_DEPTH] [2]; + } w1; + + struct { int last_dbits [2], last_delta_sign [2], bit_limit; } w2; + + struct { int ave_dbits [2], bit_limit; } w3; + + struct { + uint32_t fast_level [2], slow_level [2]; + int bits_acc [2], bitrate; + } w4; +} WavpackStream3; diff --git a/Libraries/WavPack/Files/utils.c b/Libraries/WavPack/Files/utils.c new file mode 100644 index 000000000..36d25e612 --- /dev/null +++ b/Libraries/WavPack/Files/utils.c @@ -0,0 +1,640 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// utils.c + +// This module provides general purpose utilities for the WavPack command-line +// utilities and the self-extraction module. + +#if defined(WIN32) +#include +#include +#include +#elif defined(__GNUC__) +#include +#endif + +#ifndef WIN32 +#include +#include +#endif + +#include +#include +#include +#include + +#include "wavpack.h" + + +#ifdef WIN32 + +int copy_timestamp (const char *src_filename, const char *dst_filename) +{ + FILETIME last_modified; + HANDLE src, dst; + int res = TRUE; + + if (*src_filename == '-' || *dst_filename == '-') + return res; + + src = CreateFile (src_filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + dst = CreateFile (dst_filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + if (src == INVALID_HANDLE_VALUE || dst == INVALID_HANDLE_VALUE || + !GetFileTime (src, NULL, NULL, &last_modified) || + !SetFileTime (dst, NULL, NULL, &last_modified)) + res = FALSE; + + if (src != INVALID_HANDLE_VALUE) + CloseHandle (src); + + if (dst != INVALID_HANDLE_VALUE) + CloseHandle (dst); + + return res; +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function parses a filename (with or without full path) and returns // +// a pointer to the extension (including the "."). If no extension is found // +// then NULL is returned. Extensions with more than 3 letters don't count. // +////////////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) + +static int is_second_byte (char *filespec, char *pos); + +char *filespec_ext (char *filespec) +{ + char *cp = filespec + strlen (filespec); + LANGID langid = GetSystemDefaultLangID (); + + while (--cp >= filespec) { + + if (langid == 0x411 && is_second_byte (filespec, cp)) + --cp; + + if (*cp == '\\' || *cp == ':') + return NULL; + + if (*cp == '.') { + if (strlen (cp) > 1 && strlen (cp) <= 4) + return cp; + else + return NULL; + } + } + + return NULL; +} + +#else + +char *filespec_ext (char *filespec) +{ + char *cp = filespec + strlen (filespec); + + while (--cp >= filespec) { + + if (*cp == '\\' || *cp == ':') + return NULL; + + if (*cp == '.') { + if (strlen (cp) > 1 && strlen (cp) <= 4) + return cp; + else + return NULL; + } + } + + return NULL; +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function determines if the specified filespec is a valid pathname. // +// If not, NULL is returned. If it is in the format of a pathname, then the // +// original pointer is returned. If the format is ambiguous, then a lookup // +// is performed to determine if it is in fact a valid path, and if so a "\" // +// is appended so that the pathname can be used and the original pointer is // +// returned. // +////////////////////////////////////////////////////////////////////////////// + +#if defined(__GNUC__) && !defined(WIN32) + +char *filespec_path (char *filespec) +{ + char *cp = filespec + strlen (filespec); + glob_t globs; + struct stat fstats; + + if (cp == filespec || filespec_wild (filespec)) + return NULL; + + if (*--cp == '\\' || *cp == ':') + return filespec; + + if (*cp == '.' && cp == filespec) + return strcat (filespec, "\\"); + + if (glob (filespec, GLOB_MARK|GLOB_NOSORT, NULL, &globs) == 0 && + globs.gl_pathc > 0) + { + /* test if the file is a directory */ + if (stat(globs.gl_pathv[0], &fstats) == 0 && (fstats.st_mode & S_IFDIR)) { + globfree(&globs); + filespec[0] = '\0'; + return strcat (filespec, globs.gl_pathv[0]); + } + } + globfree(&globs); + + return NULL; +} + +#else + +char *filespec_path (char *filespec) +{ + char *cp = filespec + strlen (filespec); + LANGID langid = GetSystemDefaultLangID (); + struct _finddata_t finddata; + int32_t file; + + if (cp == filespec || filespec_wild (filespec)) + return NULL; + + --cp; + + if (langid == 0x411 && is_second_byte (filespec, cp)) + --cp; + + if (*cp == '\\' || *cp == ':') + return filespec; + + if (*cp == '.' && cp == filespec) + return strcat (filespec, "\\"); + + if ((file = _findfirst (filespec, &finddata)) != -1L && + (finddata.attrib & _A_SUBDIR)) { + _findclose (file); + return strcat (filespec, "\\"); + } + if (file != -1L) + _findclose(file); + + return NULL; +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function returns non-NULL if the specified filename spec has any // +// wildcard characters. // +////////////////////////////////////////////////////////////////////////////// + +char *filespec_wild (char *filespec) +{ + return strpbrk (filespec, "*?"); +} + +////////////////////////////////////////////////////////////////////////////// +// This function parses a filename (with or without full path) and returns // +// a pointer to the actual filename, or NULL if no filename can be found. // +////////////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) + +char *filespec_name (char *filespec) +{ + char *cp = filespec + strlen (filespec); + LANGID langid = GetSystemDefaultLangID (); + + while (--cp >= filespec) { + if (langid == 0x411 && is_second_byte (filespec, cp)) + --cp; + + if (*cp == '\\' || *cp == ':') + break; + } + + if (strlen (cp + 1)) + return cp + 1; + else + return NULL; +} + +#else + +char *filespec_name (char *filespec) +{ + char *cp = filespec + strlen (filespec); + + while (--cp >= filespec) + if (*cp == '\\' || *cp == ':') + break; + + if (strlen (cp + 1)) + return cp + 1; + else + return NULL; +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function returns TRUE if "pos" is pointing to the second byte of a // +// double-byte character in the string "filespec" which is assumed to be // +// shift-JIS. // +////////////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) + +static int is_second_byte (char *filespec, char *pos) +{ + uchar *cp = pos; + + while (cp > filespec && ((cp [-1] >= 0x81 && cp [-1] <= 0x9f) || + (cp [-1] >= 0xe0 && cp [-1] <= 0xfc))) + cp--; + + return ((int) pos - (int) cp) & 1; +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function allows the user to type 'y', 'n', or 'a' (with Enter) in // +// response to a system query. The return value is the key typed as // +// lowercase (regardless of the typed case). // +////////////////////////////////////////////////////////////////////////////// + +static int waiting_input; + +char yna (void) +{ + char choice = 0; + int key; + + waiting_input = 1; + + while (1) { +#if defined(WIN32) + key = getch (); +#else + key = fgetc(stdin); +#endif + if (key == 3) { + fprintf (stderr, "^C\n"); + exit (1); + } + else if (key == '\r' || key == '\n') { + if (choice) { + fprintf (stderr, "\r\n"); + break; + } + else + fprintf (stderr, "%c", 7); + } + else if (key == 'Y' || key == 'y') { + fprintf (stderr, "%c\b", key); + choice = 'y'; + } + else if (key == 'N' || key == 'n') { + fprintf (stderr, "%c\b", key); + choice = 'n'; + } + else if (key == 'A' || key == 'a') { + fprintf (stderr, "%c\b", key); + choice = 'a'; + } + else + fprintf (stderr, "%c", 7); + } + + waiting_input = 0; + + return choice; +} + +////////////////////////////////////////////////////////////////////////////// +// Display the specified message on the console through stderr. Note that // +// the cursor may start anywhere in the line and all text already on the // +// line is erased. A terminating newline is not needed and function works // +// with printf strings and args. // +////////////////////////////////////////////////////////////////////////////// + +void error_line (char *error, ...) +{ + char error_msg [512]; + va_list argptr; + + error_msg [0] = '\r'; + va_start (argptr, error); + vsprintf (error_msg + 1, error, argptr); + va_end (argptr); + fputs (error_msg, stderr); + finish_line (); +#if 0 + { + FILE *error_log = fopen ("c:\\wavpack.log", "a+"); + + if (error_log) { + fputs (error_msg + 1, error_log); + fputc ('\n', error_log); + fclose (error_log); + } + } +#endif +} + +////////////////////////////////////////////////////////////////////////////// +// Function to intercept ^C or ^Break typed at the console. // +////////////////////////////////////////////////////////////////////////////// +#if defined(WIN32) +static int break_flag; + +BOOL WINAPI ctrl_handler (DWORD ctrl) +{ + if (ctrl == CTRL_C_EVENT) { + break_flag = TRUE; + return TRUE; + } + + if (ctrl == CTRL_BREAK_EVENT) { + + if (waiting_input) { +#ifdef __BORLANDC__ + fprintf (stderr, "^C\n"); +#endif + return FALSE; + } + else { + break_flag = TRUE; + return TRUE; + } + } + + return FALSE; +} + +////////////////////////////////////////////////////////////////////////////// +// Function to initialize console for intercepting ^C and ^Break. // +////////////////////////////////////////////////////////////////////////////// + +void setup_break (void) +{ + HANDLE hConIn = GetStdHandle (STD_INPUT_HANDLE); + + SetConsoleMode (hConIn, ENABLE_PROCESSED_INPUT); + FlushConsoleInputBuffer (hConIn); + SetConsoleCtrlHandler (ctrl_handler, TRUE); + break_flag = 0; +} + +////////////////////////////////////////////////////////////////////////////// +// Function to determine whether ^C or ^Break has been issued by user. // +////////////////////////////////////////////////////////////////////////////// + +int check_break (void) +{ + return break_flag; +} + +////////////////////////////////////////////////////////////////////////////// +// Function to clear the stderr console to the end of the current line (and // +// go to the beginning next line). // +////////////////////////////////////////////////////////////////////////////// + +void finish_line (void) +{ + HANDLE hConIn = GetStdHandle (STD_ERROR_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO coninfo; + + if (hConIn && GetConsoleScreenBufferInfo (hConIn, &coninfo)) { + char spaces = coninfo.dwSize.X - coninfo.dwCursorPosition.X; + + while (spaces--) + fputc (' ', stderr); + } + else + fputc ('\n', stderr); +} +#else +////////////////////////////////////////////////////////////////////////////// +// Function to clear the stderr console to the end of the current line (and // +// go to the beginning next line). // +////////////////////////////////////////////////////////////////////////////// + +void finish_line (void) +{ +/* char spaces = 1; + + while (spaces--) + putc (' ', stderr); + else*/ + fputc ('\n', stderr); +} + +////////////////////////////////////////////////////////////////////////////// +// Function to initialize console for intercepting ^C and ^Break. // +////////////////////////////////////////////////////////////////////////////// + +void setup_break (void) +{ +} + +////////////////////////////////////////////////////////////////////////////// +// Function to determine whether ^C or ^Break has been issued by user. // +////////////////////////////////////////////////////////////////////////////// + +int check_break (void) +{ + return 0; +} + +#endif + +//////////////////////////// File I/O Wrapper //////////////////////////////// + +int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead) +{ + uint32_t bcount; + + *lpNumberOfBytesRead = 0; + + while (nNumberOfBytesToRead) { + bcount = fread ((uchar *) lpBuffer + *lpNumberOfBytesRead, 1, nNumberOfBytesToRead, hFile); + + if (bcount) { + *lpNumberOfBytesRead += bcount; + nNumberOfBytesToRead -= bcount; + } + else + break; + } + + return !ferror (hFile); +} + +int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten) +{ + uint32_t bcount; + + *lpNumberOfBytesWritten = 0; + + while (nNumberOfBytesToWrite) { + bcount = fwrite ((uchar *) lpBuffer + *lpNumberOfBytesWritten, 1, nNumberOfBytesToWrite, hFile); + + if (bcount) { + *lpNumberOfBytesWritten += bcount; + nNumberOfBytesToWrite -= bcount; + } + else + break; + } + + return !ferror (hFile); +} + +uint32_t DoGetFileSize (FILE *hFile) +{ + struct stat statbuf; + + if (!hFile || fstat (fileno (hFile), &statbuf) || !(statbuf.st_mode & S_IFREG)) + return 0; + + return statbuf.st_size; +} + +uint32_t DoGetFilePosition (FILE *hFile) +{ + return ftell (hFile); +} + +int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos) +{ + return fseek (hFile, pos, SEEK_SET); +} + +int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode) +{ + return fseek (hFile, pos, mode); +} + +// if ungetc() is not available, a seek of -1 is fine also because we do not +// change the byte read. + +int DoUngetc (int c, FILE *hFile) +{ + return ungetc (c, hFile); +} + +int DoCloseHandle (FILE *hFile) +{ + return hFile ? !fclose (hFile) : 0; +} + +int DoTruncateFile (FILE *hFile) +{ + if (hFile) { + fflush (hFile); +#if defined(WIN32) + return !chsize (fileno (hFile), 0); +#else + return !ftruncate(fileno (hFile), 0); +#endif + } + + return 0; +} + +int DoDeleteFile (char *filename) +{ + return !remove (filename); +} + +// Convert the Unicode wide-format string into a UTF-8 string using no more +// than the specified buffer length. The wide-format string must be NULL +// terminated and the resulting string will be NULL terminated. The actual +// number of characters converted (not counting terminator) is returned, which +// may be less than the number of characters in the wide string if the buffer +// length is exceeded. + +static int WideCharToUTF8 (const ushort *Wide, uchar *pUTF8, int len) +{ + const ushort *pWide = Wide; + int outndx = 0; + + while (*pWide) { + if (*pWide < 0x80 && outndx + 1 < len) + pUTF8 [outndx++] = (uchar) *pWide++; + else if (*pWide < 0x800 && outndx + 2 < len) { + pUTF8 [outndx++] = (uchar) (0xc0 | ((*pWide >> 6) & 0x1f)); + pUTF8 [outndx++] = (uchar) (0x80 | (*pWide++ & 0x3f)); + } + else if (outndx + 3 < len) { + pUTF8 [outndx++] = (uchar) (0xe0 | ((*pWide >> 12) & 0xf)); + pUTF8 [outndx++] = (uchar) (0x80 | ((*pWide >> 6) & 0x3f)); + pUTF8 [outndx++] = (uchar) (0x80 | (*pWide++ & 0x3f)); + } + else + break; + } + + pUTF8 [outndx] = 0; + return pWide - Wide; +} + +// Convert a Ansi string into its Unicode UTF-8 format equivalent. The +// conversion is done in-place so the maximum length of the string buffer must +// be specified because the string may become longer or shorter. If the +// resulting string will not fit in the specified buffer size then it is +// truncated. + +void AnsiToUTF8 (char *string, int len) +{ + int max_chars = strlen (string); +#if defined(WIN32) + ushort *temp = (ushort *) malloc ((max_chars + 1) * 2); + + MultiByteToWideChar (CP_ACP, 0, string, -1, temp, max_chars + 1); + WideCharToUTF8 (temp, (uchar *) string, len); +#else + char *temp = malloc (len); +// memset(temp, 0, len); + char *outp = temp; + const char *inp = string; + size_t insize = max_chars; + size_t outsize = len - 1; + int err = 0; + char *old_locale; + + memset(temp, 0, len); + old_locale = setlocale (LC_CTYPE, ""); + iconv_t converter = iconv_open ("UTF-8", ""); + err = iconv (converter, &inp, &insize, &outp, &outsize); + iconv_close (converter); + setlocale (LC_CTYPE, old_locale); + + if (err == -1) { + free(temp); + return; + } + + memmove (string, temp, len); +#endif + free (temp); +} diff --git a/Libraries/WavPack/Files/wavpack.c b/Libraries/WavPack/Files/wavpack.c new file mode 100644 index 000000000..50ec1b34c --- /dev/null +++ b/Libraries/WavPack/Files/wavpack.c @@ -0,0 +1,1448 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wavpack.c + +// This is the main module for the WavPack command-line compressor. + +#if defined(WIN32) +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include + +#include "wavpack.h" +#include "md5.h" + +#ifdef __BORLANDC__ +#include +#else +#if defined (__GNUC__) && !defined(WIN32) +#include +#include +#include +#else +#include +#endif +#endif + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +static char *strdup (const char *s) + { char *d = malloc (strlen (s) + 1); return strcpy (d, s); } +#endif + +///////////////////////////// local variable storage ////////////////////////// + +static const char *sign_on = "\n" +" WAVPACK Hybrid Lossless Wavefile Compressor %s Version %s %s\n" +" Copyright (c) 1998 - 2005 Conifer Software. All Rights Reserved.\n\n"; + +static const char *usage = +" Usage: WAVPACK [-options] [@]infile[.wav]|- [[@]outfile[.wv]|outpath|-]\n" +" (default is lossless; infile may contain wildcards: ?,*)\n\n" +" Options: -a = Adobe Audition (CoolEdit) mode for 32-bit floats\n" +" -bn = enable hybrid compression, n = 2.0 to 23.9 bits/sample, or\n" +" n = 24-9600 kbits/second (kbps)\n" +" -c = create correction file (.wvc) for hybrid mode (=lossless)\n" +" -cc = maximum hybrid compression (hurts lossy quality & decode speed)\n" +" -d = delete source file if successful (use with caution!)\n" +#if defined (WIN32) +" -e = create self-extracting executable (needs wvselfx.exe)\n" +#endif +" -f = fast mode (fast, but some compromise in compression ratio)\n" +" -h = high quality (best compression in all modes, but slower)\n" +" -i = ignore length in wav header (no pipe output allowed)\n" +" -jn = joint-stereo override (0 = left/right, 1 = mid/side)\n" +" -m = compute & store MD5 signature of raw audio data\n" +" -n = calculate average and peak quantization noise (hybrid only)\n" +" -p = practical float storage (also 32-bit ints, not lossless)\n" +" -q = quiet (keep console output to a minimum)\n" +" -sn = noise shaping override (hybrid only, n = -1.0 to 1.0, 0 = off)\n" +#if defined (WIN32) +" -t = copy input file's time stamp to output file(s)\n" +#endif +" -w \"Field=Value\" = write specified metadata to APEv2 tag\n" +" -x[n] = extra encode processing (optional n = 1-6 for less/more)\n" +" -y = yes to all warnings (use with caution!)\n\n" +" Web: Visit www.wavpack.com for latest version and info\n"; + +static int overwrite_all, num_files, file_index; + +#if defined (WIN32) +static char *wvselfx_image; +static uint32_t wvselfx_size; +#endif + +/////////////////////////// local function declarations /////////////////////// + +static int pack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config); +static int pack_audio (WavpackContext *wpc, FILE *infile); +static void display_progress (double file_progress); + +#define NO_ERROR 0L +#define SOFT_ERROR 1 +#define HARD_ERROR 2 + +////////////////////////////////////////////////////////////////////////////// +// The "main" function for the command-line WavPack compressor. // +////////////////////////////////////////////////////////////////////////////// + +int main (argc, argv) int argc; char **argv; +{ + int delete_source = 0, usage_error = 0, filelist = 0, tag_next_arg = 0; + char *infilename = NULL, *outfilename = NULL, *out2filename = NULL; + char **matches = NULL; + WavpackConfig config; + int result, i; + +#if defined (WIN32) + char *selfname = malloc (strlen (*argv) + PATH_MAX); + struct _finddata_t _finddata_t; + + strcpy (selfname, *argv); +#else + glob_t globs; + struct stat fstats; +#endif + + CLEAR (config); + +#if 0 + { + char **argv_t = argv; + int argc_t = argc; + + while (--argc_t) + error_line ("%d: %s", argc - argc_t, *++argv_t); + } +#endif + + // loop through command-line arguments + + while (--argc) +#if defined (WIN32) + if ((**++argv == '-' || **argv == '/') && (*argv)[1]) +#else + if ((**++argv == '-') && (*argv)[1]) +#endif + while (*++*argv) + switch (**argv) { + + case 'Y': case 'y': + overwrite_all = 1; + break; + + case 'D': case 'd': + delete_source = 1; + break; + + case 'C': case 'c': + if (config.flags & CONFIG_CREATE_WVC) + config.flags |= CONFIG_OPTIMIZE_WVC; + else + config.flags |= CONFIG_CREATE_WVC; + + break; + + case 'X': case 'x': + config.xmode = strtol (++*argv, argv, 10); + + if (config.xmode < 0 || config.xmode > 6) { + error_line ("extra mode only goes from 1 to 6!"); + usage_error = 1; + } + else + config.flags |= CONFIG_EXTRA_MODE; + + --*argv; + break; + + case 'F': case 'f': + if (config.flags & CONFIG_FAST_FLAG) + config.flags |= CONFIG_VERY_FAST_FLAG; + else + config.flags |= CONFIG_FAST_FLAG; + + break; + + case 'H': case 'h': + if (config.flags & CONFIG_HIGH_FLAG) + config.flags |= CONFIG_VERY_HIGH_FLAG; + else + config.flags |= CONFIG_HIGH_FLAG; + + break; + + case 'N': case 'n': + config.flags |= CONFIG_CALC_NOISE; + break; + + case 'A': case 'a': + config.flags |= CONFIG_ADOBE_MODE; + break; +#if defined (WIN32) + case 'E': case 'e': + config.flags |= CONFIG_CREATE_EXE; + break; + + case 'T': case 't': + config.flags |= CONFIG_COPY_TIME; + break; +#endif + case 'P': case 'p': + config.flags |= CONFIG_SKIP_WVX; + break; + + case 'Q': case 'q': + config.flags |= CONFIG_QUIET_MODE; + break; + + case 'M': case 'm': + config.flags |= CONFIG_MD5_CHECKSUM; + break; + + case 'I': case 'i': + config.flags |= CONFIG_IGNORE_LENGTH; + break; + + case 'K': case 'k': + config.block_samples = strtol (++*argv, argv, 10); + --*argv; + break; + + case 'B': case 'b': + config.flags |= CONFIG_HYBRID_FLAG; + config.bitrate = strtod (++*argv, argv); + --*argv; + + if (config.bitrate < 2.0 || config.bitrate > 9600.0) { + error_line ("hybrid spec must be 2.0 to 9600!"); + usage_error = 1; + } + + if (config.bitrate >= 24.0) + config.flags |= CONFIG_BITRATE_KBPS; + + break; + + case 'J': case 'j': + switch (strtol (++*argv, argv, 10)) { + + case 0: + config.flags |= CONFIG_JOINT_OVERRIDE; + config.flags &= ~CONFIG_JOINT_STEREO; + break; + + case 1: + config.flags |= (CONFIG_JOINT_OVERRIDE | CONFIG_JOINT_STEREO); + break; + + default: + error_line ("-j0 or -j1 only!"); + usage_error = 1; + } + + --*argv; + break; + + case 'S': case 's': + config.shaping_weight = strtod (++*argv, argv); + + if (!config.shaping_weight) { + config.flags |= CONFIG_SHAPE_OVERRIDE; + config.flags &= ~CONFIG_HYBRID_SHAPE; + } + else if (config.shaping_weight >= -1.0 && config.shaping_weight <= 1.0) + config.flags |= (CONFIG_HYBRID_SHAPE | CONFIG_SHAPE_OVERRIDE); + else { + error_line ("-s-1.00 to -s1.00 only!"); + usage_error = 1; + } + + --*argv; + break; + + case 'W': case 'w': + tag_next_arg = 1; + break; + + default: + error_line ("illegal option: %c !", **argv); + usage_error = 1; + } + else { + if (tag_next_arg) { + char *cp = strchr (*argv, '='), *string = NULL; + + tag_next_arg = 0; + + if (cp && cp > *argv) { + int item_len = cp - *argv; + + if (cp [1] == '@') { + FILE *file = fopen (cp+2, "rb"); + + if (file) { + uint32_t bcount, file_len; + + file_len = DoGetFileSize (file); + + if (file_len < 1048576 && (string = malloc (item_len + file_len + 2)) != NULL) { + memcpy (string, *argv, item_len + 1); + + if (!DoReadFile (file, string + item_len + 1, file_len, &bcount) || bcount != file_len) { + free (string); + string = NULL; + } + else + string [item_len + file_len + 1] = 0; + } + + DoCloseHandle (file); + } + } + else + string = *argv; + } + + if (!string) { + error_line ("error in tag spec: %s !", *argv); + usage_error = 1; + } + else if (cp [1]) { + config.tag_strings = realloc (config.tag_strings, ++config.num_tag_strings * sizeof (*config.tag_strings)); + config.tag_strings [config.num_tag_strings - 1] = string; + } + } + else if (!infilename) { + infilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (infilename, *argv); + } + else if (!outfilename) { + outfilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (outfilename, *argv); + } + else if (!out2filename) { + out2filename = malloc (strlen (*argv) + PATH_MAX); + strcpy (out2filename, *argv); + } + else { + error_line ("extra unknown argument: %s !", *argv); + usage_error = 1; + } + } + + setup_break (); // set up console and detect ^C and ^Break + + // check for various command-line argument problems + + if (!(~config.flags & (CONFIG_HIGH_FLAG | CONFIG_FAST_FLAG))) { + error_line ("high and fast modes are mutually exclusive!"); + usage_error = 1; + } + + if ((config.flags & CONFIG_IGNORE_LENGTH) && outfilename && *outfilename == '-') { + error_line ("can't ignore length in header when using stdout!"); + usage_error = 1; + } + + if (config.flags & CONFIG_HYBRID_FLAG) { + if ((config.flags & CONFIG_CREATE_WVC) && outfilename && *outfilename == '-') { + error_line ("can't create correction file when using stdout!"); + usage_error = 1; + } + } + else { + if (config.flags & (CONFIG_CALC_NOISE | CONFIG_SHAPE_OVERRIDE | CONFIG_CREATE_WVC)) { + error_line ("-s, -n and -c options are for hybrid mode (-b) only!"); + usage_error = 1; + } + } + + if (!(config.flags & CONFIG_QUIET_MODE) && !usage_error) + fprintf (stderr, sign_on, VERSION_OS, VERSION_STR, DATE_STR); + + if (!infilename) { + printf ("%s", usage); + return 0; + } + + if (usage_error) { + free(infilename); + return 0; + } + + // If we are trying to create self-extracting .exe files, this is where + // we read the wvselfx.exe file into memory in preparation for pre-pending + // it to the WavPack files. + +#if defined (WIN32) + if (config.flags & CONFIG_CREATE_EXE) { + FILE *wvselfx_file; + uint32_t bcount; + + strcpy (filespec_name (selfname), "wvselfx.exe"); + + wvselfx_file = fopen (selfname, "rb"); + + if (!wvselfx_file) { + _searchenv ("wvselfx.exe", "PATH", selfname); + wvselfx_file = fopen (selfname, "rb"); + } + + if (wvselfx_file) { + wvselfx_size = DoGetFileSize (wvselfx_file); + + if (wvselfx_size && wvselfx_size != 26624 && wvselfx_size < 49152) { + wvselfx_image = malloc (wvselfx_size); + + if (!DoReadFile (wvselfx_file, wvselfx_image, wvselfx_size, &bcount) || bcount != wvselfx_size) { + free (wvselfx_image); + wvselfx_image = NULL; + } + } + + DoCloseHandle (wvselfx_file); + } + + if (!wvselfx_image) { + error_line ("wvselfx.exe file is not readable or is outdated!"); + free (wvselfx_image); + exit (1); + } + } +#endif + + // If the infile specification begins with a '@', then it actually points + // to a file that contains the names of the files to be converted. This + // was included for use by Wim Speekenbrink's frontends, but could be used + // for other purposes. + + if (infilename [0] == '@') { + FILE *list = fopen (infilename+1, "rt"); + int c; + + if (list == NULL) { + error_line ("file %s not found!", infilename+1); + free (infilename); + return 1; + } + + while ((c = getc (list)) != EOF) { + + while (c == '\n') + c = getc (list); + + if (c != EOF) { + char *fname = malloc (PATH_MAX); + int ci = 0; + + do + fname [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + fname [ci++] = '\0'; + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = realloc (fname, ci); + } + } + + fclose (list); + free (infilename); + infilename = NULL; + filelist = 1; + } + else if (*infilename != '-') { // skip this if infile is stdin (-) + if (!(config.flags & CONFIG_RAW_FLAG) && !filespec_ext (infilename)) + strcat (infilename, ".wav"); + +#ifdef NO_WILDCARDS + matches = malloc (sizeof (*matches)); + matches [num_files++] = infilename; + filelist = 1; +#else + // search for and store any filenames that match the user supplied spec + +#ifdef __BORLANDC__ + if (findfirst (infilename, &ffblk, 0) == 0) { + do { + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = strdup (ffblk.ff_name); + } while (findnext (&ffblk) == 0); + } +#elif defined (WIN32) + if ((i = _findfirst (infilename, &_finddata_t)) != -1L) { + do { + if (!(_finddata_t.attrib & _A_SUBDIR)) { + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = strdup (_finddata_t.name); + } + } while (_findnext (i, &_finddata_t) == 0); + + _findclose (i); + } +#else + i = 0; + if (glob(infilename, 0, NULL, &globs) == 0 && globs.gl_pathc > 0) { + do { + if (stat(globs.gl_pathv[i], &fstats) == 0 && !(fstats.st_mode & S_IFDIR)) { + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = strdup (globs.gl_pathv[i]); + } + } while (i++ < globs.gl_pathc); + } + globfree(&globs); +#endif +#endif + } + else { // handle case of stdin (-) + matches = malloc (sizeof (*matches)); + matches [num_files++] = infilename; + } + + // If the outfile specification begins with a '@', then it actually points + // to a file that contains the output specification. This was included for + // use by Wim Speekenbrink's frontends because certain filenames could not + // be passed on the command-line, but could be used for other purposes. + + if (outfilename && outfilename [0] == '@') { + FILE *list = fopen (outfilename+1, "rt"); + int c; + + if (list == NULL) { + error_line ("file %s not found!", outfilename+1); + free(outfilename); + return 1; + } + + while ((c = getc (list)) == '\n'); + + if (c != EOF) { + int ci = 0; + + do + outfilename [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + outfilename [ci] = '\0'; + } + else { + error_line ("output spec file is empty!"); + free(outfilename); + fclose (list); + return 1; + } + + fclose (list); + } + + if (out2filename && (num_files > 1 || !(config.flags & CONFIG_CREATE_WVC))) { + error_line ("extra unknown argument: %s !", out2filename); + return 1; + } + + // if we found any files to process, this is where we start + + if (num_files) { + char outpath, addext; + int soft_errors = 0; + + if (outfilename && *outfilename != '-') { + outpath = (filespec_path (outfilename) != NULL); + + if (num_files > 1 && !outpath) { + error_line ("%s is not a valid output path", outfilename); + free(outfilename); + return 1; + } + } + else + outpath = 0; + + addext = !outfilename || outpath || !filespec_ext (outfilename); + + // loop through and process files in list + + for (file_index = 0; file_index < num_files; ++file_index) { + if (check_break ()) + break; + + // get input filename from list + + if (filelist) + infilename = matches [file_index]; + else if (*infilename != '-') { + *filespec_name (infilename) = '\0'; + strcat (infilename, matches [file_index]); + } + + // generate output filename + + if (outpath) { + strcat (outfilename, filespec_name (matches [file_index])); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + else if (!outfilename) { + outfilename = malloc (strlen (infilename) + 10); + strcpy (outfilename, infilename); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + + if (addext && *outfilename != '-') + strcat (outfilename, (config.flags & CONFIG_CREATE_EXE) ? ".exe" : ".wv"); + + // if "correction" file is desired, generate name for that + + if (config.flags & CONFIG_CREATE_WVC) { + if (!out2filename) { + out2filename = malloc (strlen (outfilename) + 10); + strcpy (out2filename, outfilename); + } + else { + char *temp = malloc (strlen (outfilename) + PATH_MAX); + + strcpy (temp, outfilename); + strcpy (filespec_name (temp), filespec_name (out2filename)); + strcpy (out2filename, temp); + free (temp); + } + + if (filespec_ext (out2filename)) + *filespec_ext (out2filename) = '\0'; + + strcat (out2filename, ".wvc"); + } + else + out2filename = NULL; + + if (num_files > 1) + fprintf (stderr, "\n%s:\n", infilename); + + result = pack_file (infilename, outfilename, out2filename, &config); + + if (result == HARD_ERROR) + break; + else if (result == SOFT_ERROR) + ++soft_errors; + + // delete source file if that option is enabled + + if (result == NO_ERROR && delete_source) + error_line ("%s source file %s", DoDeleteFile (infilename) ? + "deleted" : "can't delete", infilename); + + // clean up in preparation for potentially another file + + if (outpath) + *filespec_name (outfilename) = '\0'; + else if (*outfilename != '-') { + free (outfilename); + outfilename = NULL; + } + + if (out2filename) { + free (out2filename); + out2filename = NULL; + } + + free (matches [file_index]); + } + + if (num_files > 1) { + if (soft_errors) + fprintf (stderr, "\n **** warning: errors occurred in %d of %d files! ****\n", soft_errors, num_files); + else if (!(config.flags & CONFIG_QUIET_MODE)) + fprintf (stderr, "\n **** %d files successfully processed ****\n", num_files); + } + + free (matches); + } + else + error_line (filespec_wild (infilename) ? "nothing to do!" : + "file %s not found!", infilename); + + if (outfilename) + free(outfilename); + +#ifdef DEBUG_ALLOC + error_line ("malloc_count = %d", dump_alloc ()); +#endif + + return 0; +} + +// This structure and function are used to write completed WavPack blocks in +// a device independent way. + +typedef struct { + uint32_t bytes_written, first_block_size; + FILE *file; + int error; +} write_id; + +static int write_block (void *id, void *data, int32_t length) +{ + write_id *wid = (write_id *) id; + uint32_t bcount; + + if (wid->error) + return FALSE; + + if (wid && wid->file && data && length) { + if (!DoWriteFile (wid->file, data, length, &bcount) || bcount != length) { + DoTruncateFile (wid->file); + DoCloseHandle (wid->file); + wid->file = NULL; + wid->error = 1; + return FALSE; + } + else { + wid->bytes_written += length; + + if (!wid->first_block_size) + wid->first_block_size = bcount; + } + } + + return TRUE; +} + +// This function packs a single file "infilename" and stores the result at +// "outfilename". If "out2filename" is specified, then the "correction" +// file would go there. The files are opened and closed in this function +// and the "config" structure specifies the mode of compression. + +static int pack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config) +{ + uint32_t total_samples = 0, wrapper_size = 0, bcount; + WavpackConfig loc_config = *config; + RiffChunkHeader riff_chunk_header; + write_id wv_file, wvc_file; + ChunkHeader chunk_header; + WaveHeader WaveHeader; + WavpackContext *wpc; + double dtime; + FILE *infile; + int result; + +#ifdef __BORLANDC__ + struct time time1, time2; +#elif defined(WIN32) + struct _timeb time1, time2; +#else + struct timeval time1, time2; + struct timezone timez; +#endif + + CLEAR (wv_file); + CLEAR (wvc_file); + wpc = WavpackOpenFileOutput (write_block, &wv_file, out2filename ? &wvc_file : NULL); + + // open the source file for reading + + if (*infilename == '-') { + infile = stdin; +#if defined(WIN32) + setmode (fileno (stdin), O_BINARY); +#endif + } + else if ((infile = fopen (infilename, "rb")) == NULL) { + error_line ("can't open file %s!", infilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + // check both output files for overwrite warning required + + if (*outfilename != '-' && !overwrite_all && (wv_file.file = fopen (outfilename, "rb")) != NULL) { + DoCloseHandle (wv_file.file); + fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); + SetConsoleTitle ("overwrite?"); + + switch (yna ()) { + case 'n': + DoCloseHandle (infile); + WavpackCloseFile (wpc); + return SOFT_ERROR; + + case 'a': + overwrite_all = 1; + } + } + + if (out2filename && !overwrite_all && (wvc_file.file = fopen (out2filename, "rb")) != NULL) { + DoCloseHandle (wvc_file.file); + fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (out2filename)); + SetConsoleTitle ("overwrite?"); + + switch (yna ()) { + + case 'n': + DoCloseHandle (infile); + WavpackCloseFile (wpc); + return SOFT_ERROR; + + case 'a': + overwrite_all = 1; + } + } + +#ifdef __BORLANDC__ + gettime (&time1); +#elif defined(WIN32) + _ftime (&time1); +#else + gettimeofday(&time1,&timez); +#endif + + // open output file for writing + + if (*outfilename == '-') { + wv_file.file = stdout; +#if defined(WIN32) + setmode (fileno (stdout), O_BINARY); +#endif + } + else if ((wv_file.file = fopen (outfilename, "w+b")) == NULL) { + error_line ("can't create file %s!", outfilename); + DoCloseHandle (infile); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + if (!(loc_config.flags & CONFIG_QUIET_MODE)) { + if (*outfilename == '-') + fprintf (stderr, "packing %s to stdout,", *infilename == '-' ? "stdin" : FN_FIT (infilename)); + else if (out2filename) + fprintf (stderr, "creating %s (+%s),", FN_FIT (outfilename), filespec_ext (out2filename)); + else + fprintf (stderr, "creating %s,", FN_FIT (outfilename)); + } + +#if defined (WIN32) + if (loc_config.flags & CONFIG_CREATE_EXE) + if (!DoWriteFile (wv_file.file, wvselfx_image, wvselfx_size, &bcount) || bcount != wvselfx_size) { + error_line ("can't write WavPack data, disk probably full!"); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } +#endif + + // if not in "raw" mode, read (and copy to output) initial RIFF form header + + if (!(loc_config.flags & CONFIG_RAW_FLAG)) { + if ((!DoReadFile (infile, &riff_chunk_header, sizeof (RiffChunkHeader), &bcount) || + bcount != sizeof (RiffChunkHeader) || strncmp (riff_chunk_header.ckID, "RIFF", 4) || + strncmp (riff_chunk_header.formType, "WAVE", 4))) { + error_line ("%s is not a valid .WAV file!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!WavpackAddWrapper (wpc, &riff_chunk_header, sizeof (RiffChunkHeader))) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + wrapper_size += sizeof (RiffChunkHeader); + } + + // if not in "raw" mode, loop through all elements of the RIFF wav header + // (until the data chuck) and copy them to the output file + + while (!(loc_config.flags & CONFIG_RAW_FLAG)) { + + if (!DoReadFile (infile, &chunk_header, sizeof (ChunkHeader), &bcount) || + bcount != sizeof (ChunkHeader)) { + error_line ("%s is not a valid .WAV file!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!WavpackAddWrapper (wpc, &chunk_header, sizeof (ChunkHeader))) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + wrapper_size += sizeof (ChunkHeader); + little_endian_to_native (&chunk_header, ChunkHeaderFormat); + + // if it's the format chunk, we want to get some info out of there and + // make sure it's a .wav file we can handle + + if (!strncmp (chunk_header.ckID, "fmt ", 4)) { + int supported = TRUE, format; + + if (chunk_header.ckSize < 16 || chunk_header.ckSize > sizeof (WaveHeader) || + !DoReadFile (infile, &WaveHeader, chunk_header.ckSize, &bcount) || + bcount != chunk_header.ckSize) { + error_line ("%s is not a valid .WAV file!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!WavpackAddWrapper (wpc, &WaveHeader, chunk_header.ckSize)) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + wrapper_size += chunk_header.ckSize; + little_endian_to_native (&WaveHeader, WaveHeaderFormat); + +#if 0 + error_line ("format tag size = %d", chunk_header.ckSize); + error_line ("FormatTag = %x, NumChannels = %d, BitsPerSample = %d", + WaveHeader.FormatTag, WaveHeader.NumChannels, WaveHeader.BitsPerSample); + error_line ("BlockAlign = %d, SampleRate = %d, BytesPerSecond = %d", + WaveHeader.BlockAlign, WaveHeader.SampleRate, WaveHeader.BytesPerSecond); + + if (chunk_header.ckSize > 16) + error_line ("cbSize = %d, ValidBitsPerSample = %d", WaveHeader.cbSize, + WaveHeader.ValidBitsPerSample); + + if (chunk_header.ckSize > 20) + error_line ("ChannelMask = %x, SubFormat = %d", + WaveHeader.ChannelMask, WaveHeader.SubFormat); +#endif + + if (chunk_header.ckSize > 16 && WaveHeader.cbSize == 2) + loc_config.flags |= CONFIG_ADOBE_MODE; + + format = (WaveHeader.FormatTag == 0xfffe && chunk_header.ckSize == 40) ? + WaveHeader.SubFormat : WaveHeader.FormatTag; + + loc_config.bits_per_sample = chunk_header.ckSize == 40 ? + WaveHeader.ValidBitsPerSample : WaveHeader.BitsPerSample; + + if (format != 1 && format != 3) + supported = FALSE; + + if (!WaveHeader.NumChannels || + WaveHeader.BlockAlign / WaveHeader.NumChannels > 4) + supported = FALSE; + + if (loc_config.bits_per_sample < 1 || loc_config.bits_per_sample > 32) + supported = FALSE; + + if (!supported) { + error_line ("%s is an unsupported .WAV format!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + if (chunk_header.ckSize < 40) { + if (WaveHeader.NumChannels <= 2) + loc_config.channel_mask = 0x5 - WaveHeader.NumChannels; + else + loc_config.channel_mask = (1 << WaveHeader.NumChannels) - 1; + } + else + loc_config.channel_mask = WaveHeader.ChannelMask; + + if (format == 3) + loc_config.float_norm_exp = 127; + else if ((loc_config.flags & CONFIG_ADOBE_MODE) && + WaveHeader.BlockAlign / WaveHeader.NumChannels == 4) { + if (WaveHeader.BitsPerSample == 24) + loc_config.float_norm_exp = 127 + 23; + else if (WaveHeader.BitsPerSample == 32) + loc_config.float_norm_exp = 127 + 15; + } + } + else if (!strncmp (chunk_header.ckID, "data", 4)) { + + // on the data chunk, get size and exit loop + + total_samples = chunk_header.ckSize / WaveHeader.BlockAlign; + break; + } + else { // just copy unknown chunks to output file + + int bytes_to_copy = (chunk_header.ckSize + 1) & ~1L; + char *buff = malloc (bytes_to_copy); +#if 0 + error_line ("extra unknown chunk \"%c%c%c%c\" of %d bytes", + chunk_header.ckID [0], chunk_header.ckID [1], chunk_header.ckID [2], + chunk_header.ckID [3], chunk_header.ckSize); +#endif + if (!DoReadFile (infile, buff, bytes_to_copy, &bcount) || + bcount != bytes_to_copy || !WavpackAddWrapper (wpc, buff, bytes_to_copy)) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + free (buff); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + wrapper_size += bytes_to_copy; + free (buff); + } + } + + loc_config.bytes_per_sample = WaveHeader.BlockAlign / WaveHeader.NumChannels; + loc_config.num_channels = WaveHeader.NumChannels; + loc_config.sample_rate = WaveHeader.SampleRate; + + WavpackSetConfiguration (wpc, &loc_config, total_samples); + + // if we are creating a "correction" file, open it now for writing + + if (out2filename) { + if ((wvc_file.file = fopen (out2filename, "w+b")) == NULL) { + error_line ("can't create correction file!"); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + } + + // pack the audio portion of the file now + + result = pack_audio (wpc, infile); + + // if everything went well (and we're not ignoring length) try to read + // anything else that might be appended to the audio data and write that + // to the WavPack metadata as "wrapper" + + if (result == NO_ERROR && !(loc_config.flags & CONFIG_IGNORE_LENGTH)) { + uchar buff [16]; + + while (DoReadFile (infile, buff, sizeof (buff), &bcount) && bcount) + if (!WavpackAddWrapper (wpc, buff, bcount)) { + error_line ("%s", wpc->error_message); + result = HARD_ERROR; + break; + } + } + + DoCloseHandle (infile); // we're now done with input file, so close + + // we're now done with any WavPack blocks, so flush any remaining data + + if (result == NO_ERROR && !WavpackFlushSamples (wpc)) { + error_line ("%s", wpc->error_message); + result = HARD_ERROR; + } + + // if still no errors, check to see if we need to create & write a tag + // (which is NOT stored in regular WavPack blocks) + + if (result == NO_ERROR && config->num_tag_strings) { + int i; + + for (i = 0; i < config->num_tag_strings; ++i) { + int item_len = strchr (config->tag_strings [i], '=') - config->tag_strings [i]; + int value_len = strlen (config->tag_strings [i]) - item_len - 1; + + if (value_len) { + char *item = malloc (item_len + 1); + char *value = malloc (value_len * 2 + 1); + + strncpy (item, config->tag_strings [i], item_len); + item [item_len] = 0; + strcpy (value, config->tag_strings [i] + item_len + 1); + AnsiToUTF8 (value, value_len * 2 + 1); + WavpackAppendTagItem (wpc, item, value); + free (value); + free (item); + } + } + + if (!WavpackWriteTag (wpc)) { + error_line ("%s", wpc->error_message); + result = HARD_ERROR; + } + } + + // At this point we're done writing to the output files. However, in some + // situations we might have to back up and re-write the initial blocks. + // Currently the only case is if we're ignoring length. + + if (result == NO_ERROR && WavpackGetNumSamples (wpc) != WavpackGetSampleIndex (wpc)) { + if (loc_config.flags & CONFIG_IGNORE_LENGTH) { + char *block_buff = malloc (wv_file.first_block_size); + + if (block_buff && !DoSetFilePositionAbsolute (wv_file.file, 0) && + DoReadFile (wv_file.file, block_buff, wv_file.first_block_size, &bcount) && + bcount == wv_file.first_block_size && !strncmp (block_buff, "wvpk", 4)) { + + WavpackUpdateNumSamples (wpc, block_buff); + + if (WavpackGetWrapperLocation (block_buff)) { + RiffChunkHeader *riffhdr = WavpackGetWrapperLocation (block_buff); + ChunkHeader *datahdr = (ChunkHeader *)((char *) riffhdr + wrapper_size - sizeof (ChunkHeader)); + uint32_t data_size = WavpackGetSampleIndex (wpc) * WavpackGetNumChannels (wpc) * WavpackGetBytesPerSample (wpc); + + if (!strncmp (riffhdr->ckID, "RIFF", 4)) { + little_endian_to_native (riffhdr, ChunkHeaderFormat); + riffhdr->ckSize = wrapper_size + data_size; + native_to_little_endian (riffhdr, ChunkHeaderFormat); + } + + if (!strncmp (datahdr->ckID, "data", 4)) { + little_endian_to_native (datahdr, ChunkHeaderFormat); + datahdr->ckSize = data_size; + native_to_little_endian (datahdr, ChunkHeaderFormat); + } + } + + if (DoSetFilePositionAbsolute (wv_file.file, 0) || + !DoWriteFile (wv_file.file, block_buff, wv_file.first_block_size, &bcount) || + bcount != wv_file.first_block_size) { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + + free (block_buff); + } + else { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + + if (result == NO_ERROR && wvc_file.file) { + block_buff = malloc (wvc_file.first_block_size); + + if (block_buff && !DoSetFilePositionAbsolute (wvc_file.file, 0) && + DoReadFile (wvc_file.file, block_buff, wvc_file.first_block_size, &bcount) && + bcount == wvc_file.first_block_size && !strncmp (block_buff, "wvpk", 4)) { + + WavpackUpdateNumSamples (wpc, block_buff); + + if (DoSetFilePositionAbsolute (wvc_file.file, 0) || + !DoWriteFile (wvc_file.file, block_buff, wvc_file.first_block_size, &bcount) || + bcount != wvc_file.first_block_size) { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + } + else { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + + free (block_buff); + } + + if (result == NO_ERROR) + error_line ("warning: length was %s by %d samples, corrected", + WavpackGetSampleIndex (wpc) < total_samples ? "short" : "long", + abs (total_samples - WavpackGetSampleIndex (wpc))); + } + else { + error_line ("couldn't read all samples, file may be corrupt!!"); + result = SOFT_ERROR; + } + } + + // at this point we're done with the files, so close 'em whether there + // were any other errors or not + + if (!DoCloseHandle (wv_file.file)) { + error_line ("can't close WavPack file!"); + + if (result == NO_ERROR) + result = SOFT_ERROR; + } + + if (out2filename && !DoCloseHandle (wvc_file.file)) { + error_line ("can't close correction file!"); + + if (result == NO_ERROR) + result = SOFT_ERROR; + } + + // if there were any errors, delete the output files, close the context, + // and return the error + + if (result != NO_ERROR) { + DoDeleteFile (outfilename); + + if (out2filename) + DoDeleteFile (out2filename); + + WavpackCloseFile (wpc); + return result; + } + +#if defined (WIN32) + if (result == NO_ERROR && (loc_config.flags & CONFIG_COPY_TIME)) + if (!copy_timestamp (infilename, outfilename) || + (out2filename && !copy_timestamp (infilename, out2filename))) + error_line ("failure copying time stamp!"); +#endif + + // compute and display the time consumed along with some other details of + // the packing operation, and then return NO_ERROR + +#ifdef __BORLANDC__ + gettime (&time2); + dtime = time2.ti_sec * 100.0 + time2.ti_hund + time2.ti_min * 6000.0 + time2.ti_hour * 360000.00; + dtime -= time1.ti_sec * 100.0 + time1.ti_hund + time1.ti_min * 6000.0 + time1.ti_hour * 360000.00; + + if ((dtime /= 100.0) < 0.0) + dtime += 86400.0; +#elif defined(WIN32) + _ftime (&time2); + dtime = time2.time + time2.millitm / 1000.0; + dtime -= time1.time + time1.millitm / 1000.0; +#else + gettimeofday(&time2,&timez); + dtime = time2.tv_sec + time2.tv_usec / 1000000.0; + dtime -= time1.tv_sec + time1.tv_usec / 1000000.0; +#endif + + if ((loc_config.flags & CONFIG_CALC_NOISE) && pack_noise (wpc, NULL) > 0.0) { + int full_scale_bits = WavpackGetBitsPerSample (wpc); + double full_scale_rms = 0.5, sum, peak; + + while (full_scale_bits--) + full_scale_rms *= 2.0; + + full_scale_rms = full_scale_rms * (full_scale_rms - 1.0) * 0.5; + sum = pack_noise (wpc, &peak); + + error_line ("ave noise = %.2f dB, peak noise = %.2f dB", + log10 (sum / WavpackGetNumSamples (wpc) / full_scale_rms) * 10, + log10 (peak / full_scale_rms) * 10); + } + + if (!(loc_config.flags & CONFIG_QUIET_MODE)) { + char *file, *fext, *oper, *cmode, cratio [16] = ""; + + if (outfilename && *outfilename != '-') { + file = FN_FIT (outfilename); + fext = wvc_file.bytes_written ? " (+.wvc)" : ""; + oper = "created"; + } + else { + file = (*infilename == '-') ? "stdin" : FN_FIT (infilename); + fext = ""; + oper = "packed"; + } + + if (WavpackLossyBlocks (wpc)) { + cmode = "lossy"; + + if (WavpackGetAverageBitrate (wpc, TRUE) != 0.0) + sprintf (cratio, ", %d kbps", (int) (WavpackGetAverageBitrate (wpc, TRUE) / 1000.0)); + } + else { + cmode = "lossless"; + + if (WavpackGetRatio (wpc) != 0.0) + sprintf (cratio, ", %.2f%%", 100.0 - WavpackGetRatio (wpc) * 100.0); + } + + error_line ("%s %s%s in %.2f secs (%s%s)", oper, file, fext, dtime, cmode, cratio); + } + + WavpackCloseFile (wpc); + return NO_ERROR; +} + +// This function handles the actual audio data compression. It assumes that the +// input file is positioned at the beginning of the audio data and that the +// WavPack configuration has been set. This is where the conversion from RIFF +// little-endian standard the executing processor's format is done and where +// (if selected) the MD5 sum is calculated and displayed. + +#define INPUT_SAMPLES 65536 + +static int pack_audio (WavpackContext *wpc, FILE *infile) +{ + uint32_t samples_remaining, samples_read = 0; + double progress = -1.0; + int bytes_per_sample; + int32_t *sample_buffer; + uchar *input_buffer; + MD5_CTX md5_context; + + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) + MD5Init (&md5_context); + + WavpackPackInit (wpc); + bytes_per_sample = WavpackGetBytesPerSample (wpc) * WavpackGetNumChannels (wpc); + input_buffer = malloc (INPUT_SAMPLES * bytes_per_sample); + sample_buffer = malloc (INPUT_SAMPLES * sizeof (int32_t) * WavpackGetNumChannels (wpc)); + samples_remaining = WavpackGetNumSamples (wpc); + + while (1) { + uint32_t bytes_to_read, bytes_read = 0; + uint sample_count; + + if ((wpc->config.flags & CONFIG_IGNORE_LENGTH) || samples_remaining > INPUT_SAMPLES) + bytes_to_read = INPUT_SAMPLES * bytes_per_sample; + else + bytes_to_read = samples_remaining * bytes_per_sample; + + samples_remaining -= bytes_to_read / bytes_per_sample; + DoReadFile (infile, input_buffer, bytes_to_read, &bytes_read); + samples_read += sample_count = bytes_read / bytes_per_sample; + + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) + MD5Update (&md5_context, input_buffer, bytes_read); + + if (!sample_count) + break; + + if (sample_count) { + uint cnt = sample_count * WavpackGetNumChannels (wpc); + uchar *sptr = input_buffer; + int32_t *dptr = sample_buffer; + + switch (WavpackGetBytesPerSample (wpc)) { + + case 1: + while (cnt--) + *dptr++ = *sptr++ - 128; + + break; + + case 2: + while (cnt--) { + *dptr++ = sptr [0] | ((int32_t)(char) sptr [1] << 8); + sptr += 2; + } + + break; + + case 3: + while (cnt--) { + *dptr++ = sptr [0] | ((int32_t) sptr [1] << 8) | ((int32_t)(char) sptr [2] << 16); + sptr += 3; + } + + break; + + case 4: + while (cnt--) { + *dptr++ = sptr [0] | ((int32_t) sptr [1] << 8) | ((int32_t) sptr [2] << 16) | ((int32_t)(char) sptr [3] << 24); + sptr += 4; + } + + break; + } + } + + if (!WavpackPackSamples (wpc, sample_buffer, sample_count)) { + error_line ("%s", wpc->error_message); + free (sample_buffer); + free (input_buffer); + return HARD_ERROR; + } + + if (check_break ()) { + fprintf (stderr, "^C\n"); + free (sample_buffer); + free (input_buffer); + return SOFT_ERROR; + } + + if (WavpackGetProgress (wpc) != -1.0 && + progress != floor (WavpackGetProgress (wpc) * 100.0 + 0.5)) { + int nobs = progress == -1.0; + + progress = WavpackGetProgress (wpc); + display_progress (progress); + progress = floor (progress * 100.0 + 0.5); + + if (!(wpc->config.flags & CONFIG_QUIET_MODE)) + fprintf (stderr, "%s%3d%% done...", + nobs ? " " : "\b\b\b\b\b\b\b\b\b\b\b\b", (int) progress); + } + } + + free (sample_buffer); + free (input_buffer); + + if (!WavpackFlushSamples (wpc)) { + error_line ("%s", wpc->error_message); + return HARD_ERROR; + } + + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) { + char md5_string [] = "original md5 signature: 00000000000000000000000000000000"; + uchar md5_digest [16]; + int i; + + MD5Final (md5_digest, &md5_context); + + for (i = 0; i < 16; ++i) + sprintf (md5_string + 24 + (i * 2), "%02x", md5_digest [i]); + + if (!(wpc->config.flags & CONFIG_QUIET_MODE)) + error_line (md5_string); + + WavpackStoreMD5Sum (wpc, md5_digest); + } + + return NO_ERROR; +} + +////////////////////////////////////////////////////////////////////////////// +// This function displays the progress status on the title bar of the DOS // +// window that WavPack is running in. The "file_progress" argument is for // +// the current file only and ranges from 0 - 1; this function takes into // +// account the total number of files to generate a batch progress number. // +////////////////////////////////////////////////////////////////////////////// + +static void display_progress (double file_progress) +{ + char title [40]; + + file_progress = (file_index + file_progress) / num_files; + sprintf (title, "%d%% (WavPack)", (int) ((file_progress * 100.0) + 0.5)); + SetConsoleTitle (title); +} diff --git a/Libraries/WavPack/Files/wavpack.h b/Libraries/WavPack/Files/wavpack.h new file mode 100644 index 000000000..e2c4274ac --- /dev/null +++ b/Libraries/WavPack/Files/wavpack.h @@ -0,0 +1,656 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wavpack.h + +#ifndef WAVPACK_H +#define WAVPACK_H + +#if defined(WIN32) +#define FASTCALL __fastcall +#else +#define FASTCALL +#define SetConsoleTitle(x) +#endif + +#include + +// This header file contains all the definitions required by WavPack. + +#if defined(_WIN32) && !defined(__MINGW32__) +#include +typedef unsigned __int64 uint64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int8 uint8_t; +typedef __int64 int64_t; +typedef __int32 int32_t; +typedef __int16 int16_t; +typedef __int8 int8_t; +typedef float float32_t; +#else +#include +#endif + +typedef unsigned char uchar; + +#if !defined(__GNUC__) || defined(WIN32) +typedef unsigned short ushort; +typedef unsigned int uint; +#endif + +#ifndef PATH_MAX +#ifdef MAX_PATH +#define PATH_MAX MAX_PATH +#elif defined (MAXPATHLEN) +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +// This structure is used to access the individual fields of 32-bit ieee +// floating point numbers. This will not be compatible with compilers that +// allocate bit fields from the most significant bits, although I'm not sure +// how common that is. + +typedef struct { + unsigned mantissa : 23; + unsigned exponent : 8; + unsigned sign : 1; +} f32; + +#include + +#define FALSE 0 +#define TRUE 1 + +#if defined(WIN32) +#undef VERSION_OS +#define VERSION_OS "Win32" +#endif +#define VERSION_STR "4.2 " +#define DATE_STR "2005-04-02" + +// ID3v1 and APEv2 TAG formats (may occur at the end of WavPack files) + +typedef struct { + uchar tag_id [3], title [30], artist [30], album [30]; + uchar year [4], comment [30], genre; +} ID3_Tag; + +typedef struct { + char ID [8]; + int32_t version, length, item_count, flags; + char res [8]; +} APE_Tag_Hdr; + +#define APE_Tag_Hdr_Format "8LLLL" + +typedef struct { + ID3_Tag id3_tag; + APE_Tag_Hdr ape_tag_hdr; + char *ape_tag_data; +} M_Tag; + +// RIFF / wav header formats (these occur at the beginning of both wav files +// and pre-4.0 WavPack files that are not in the "raw" mode) + +typedef struct { + char ckID [4]; + uint32_t ckSize; + char formType [4]; +} RiffChunkHeader; + +typedef struct { + char ckID [4]; + uint32_t ckSize; +} ChunkHeader; + +#define ChunkHeaderFormat "4L" + +typedef struct { + ushort FormatTag, NumChannels; + uint32_t SampleRate, BytesPerSecond; + ushort BlockAlign, BitsPerSample; + ushort cbSize, ValidBitsPerSample; + int32_t ChannelMask; + ushort SubFormat; + char GUID [14]; +} WaveHeader; + +#define WaveHeaderFormat "SSLLSSSSLS" + +////////////////////////////// WavPack Header ///////////////////////////////// + +// Note that this is the ONLY structure that is written to (or read from) +// WavPack 4.0 files, and is the preamble to every block in both the .wv +// and .wvc files. + +typedef struct { + char ckID [4]; + uint32_t ckSize; + short version; + uchar track_no, index_no; + uint32_t total_samples, block_index, block_samples, flags, crc; +} WavpackHeader; + +#define WavpackHeaderFormat "4LS2LLLLL" + +// or-values for "flags" + +#define BYTES_STORED 3 // 1-4 bytes/sample +#define MONO_FLAG 4 // not stereo +#define HYBRID_FLAG 8 // hybrid mode +#define JOINT_STEREO 0x10 // joint stereo +#define CROSS_DECORR 0x20 // no-delay cross decorrelation +#define HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) +#define FLOAT_DATA 0x80 // ieee 32-bit floating point data + +#define INT32_DATA 0x100 // special extended int handling +#define HYBRID_BITRATE 0x200 // bitrate noise (hybrid mode only) +#define HYBRID_BALANCE 0x400 // balance noise (hybrid stereo mode only) + +#define INITIAL_BLOCK 0x800 // initial block of multichannel segment +#define FINAL_BLOCK 0x1000 // final block of multichannel segment + +#define SHIFT_LSB 13 +#define SHIFT_MASK (0x1fL << SHIFT_LSB) + +#define MAG_LSB 18 +#define MAG_MASK (0x1fL << MAG_LSB) + +#define SRATE_LSB 23 +#define SRATE_MASK (0xfL << SRATE_LSB) + +#define IGNORED_FLAGS 0x18000000 // reserved, but ignore if encountered +#define NEW_SHAPING 0x20000000 // use IIR filter for negative shaping +#define UNKNOWN_FLAGS 0xC0000000 // also reserved, but refuse decode if + // encountered + +//////////////////////////// WavPack Metadata ///////////////////////////////// + +// This is an internal representation of metadata. + +typedef struct { + int32_t byte_length; + void *data; + uchar id; +} WavpackMetadata; + +#define ID_OPTIONAL_DATA 0x20 +#define ID_ODD_SIZE 0x40 +#define ID_LARGE 0x80 + +#define ID_DUMMY 0x0 +#define ID_ENCODER_INFO 0x1 +#define ID_DECORR_TERMS 0x2 +#define ID_DECORR_WEIGHTS 0x3 +#define ID_DECORR_SAMPLES 0x4 +#define ID_ENTROPY_VARS 0x5 +#define ID_HYBRID_PROFILE 0x6 +#define ID_SHAPING_WEIGHTS 0x7 +#define ID_FLOAT_INFO 0x8 +#define ID_INT32_INFO 0x9 +#define ID_WV_BITSTREAM 0xa +#define ID_WVC_BITSTREAM 0xb +#define ID_WVX_BITSTREAM 0xc +#define ID_CHANNEL_INFO 0xd + +#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1) +#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2) +#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3) +#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4) +#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5) +#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6) + +///////////////////////// WavPack Configuration /////////////////////////////// + +// This internal structure is used during encode to provide configuration to +// the encoding engine and during decoding to provide fle information back to +// the higher level functions. Not all fields are used in both modes. + +typedef struct { + float bitrate, shaping_weight; + int bits_per_sample, bytes_per_sample; + int qmode, flags, xmode, num_channels, float_norm_exp; + int32_t block_samples, extra_flags, sample_rate, channel_mask; + uchar md5_checksum [16], md5_read; + int num_tag_strings; + char **tag_strings; +} WavpackConfig; + +#define CONFIG_BYTES_STORED 3 // 1-4 bytes/sample +#define CONFIG_MONO_FLAG 4 // not stereo +#define CONFIG_HYBRID_FLAG 8 // hybrid mode +#define CONFIG_JOINT_STEREO 0x10 // joint stereo +#define CONFIG_CROSS_DECORR 0x20 // no-delay cross decorrelation +#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) +#define CONFIG_FLOAT_DATA 0x80 // ieee 32-bit floating point data + +#define CONFIG_ADOBE_MODE 0x100 // "adobe" mode for 32-bit floats +#define CONFIG_FAST_FLAG 0x200 // fast mode +#define CONFIG_VERY_FAST_FLAG 0x400 // double fast +#define CONFIG_HIGH_FLAG 0x800 // high quality mode +#define CONFIG_VERY_HIGH_FLAG 0x1000 // double high (not used yet) +#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample +#define CONFIG_AUTO_SHAPING 0x4000 // automatic noise shaping +#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified +#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified +#define CONFIG_COPY_TIME 0x20000 // copy file-time from source +#define CONFIG_CREATE_EXE 0x40000 // create executable +#define CONFIG_CREATE_WVC 0x80000 // create correction file +#define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression +#define CONFIG_QUALITY_MODE 0x200000 // psychoacoustic quality mode +#define CONFIG_RAW_FLAG 0x400000 // raw mode (not implemented yet) +#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode +#define CONFIG_LOSSY_MODE 0x1000000 // obsolete (for information) +#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode +#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints +#define CONFIG_MD5_CHECKSUM 0x8000000 // compute & store MD5 signature +#define CONFIG_QUIET_MODE 0x10000000 // don't report progress % +#define CONFIG_IGNORE_LENGTH 0x20000000 // ignore length in wav header + +#define EXTRA_SCAN_ONLY 1 +#define EXTRA_STEREO_MODES 2 +//#define EXTRA_CHECK_TERMS 4 +#define EXTRA_TRY_DELTAS 8 +#define EXTRA_ADJUST_DELTAS 16 +#define EXTRA_SORT_FIRST 32 +#define EXTRA_BRANCHES 0x1c0 +#define EXTRA_SKIP_8TO16 512 +#define EXTRA_TERMS 0x3c00 +#define EXTRA_DUMP_TERMS 16384 +#define EXTRA_SORT_LAST 32768 + +//////////////////////////////// WavPack Stream /////////////////////////////// + +// This internal structure contains everything required to handle a WavPack +// "stream", which is defined as a stereo or mono stream of audio samples. For +// multichannel audio several of these would be required. Each stream contains +// pointers to hold a complete allocated block of WavPack data, although it's +// possible to decode WavPack blocks without buffering an entire block. + +typedef struct bs { + uchar *buf, *end, *ptr; + void (*wrap)(struct bs *bs); + int error, bc; + uint32_t sr; +} Bitstream; + +#define MAX_STREAMS 8 +#define MAX_NTERMS 16 +#define MAX_TERM 8 + +struct decorr_pass { + int term, delta, weight_A, weight_B; + int32_t samples_A [MAX_TERM], samples_B [MAX_TERM]; + int32_t aweight_A, aweight_B; +#ifdef PACK + int32_t sum_A, sum_B, min, max; +#endif +}; + +typedef struct { + WavpackHeader wphdr; + + uchar *blockbuff, *blockend; + uchar *block2buff, *block2end; + int32_t *sample_buffer; + + uint32_t sample_index, crc, crc_x, crc_wvx; + Bitstream wvbits, wvcbits, wvxbits; + int bits, num_terms, mute_error; + float delta_decay; + + uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups; + uchar float_flags, float_shift, float_max_exp, float_norm_exp; + + struct { + int32_t shaping_acc [2], shaping_delta [2], error [2]; + double noise_sum, noise_ave, noise_max; + } dc; + + struct decorr_pass decorr_passes [MAX_NTERMS]; + + struct { + uint32_t bitrate_delta [2], bitrate_acc [2]; + uint32_t median [3] [2], slow_level [2], error_limit [2]; + uint32_t pend_data, holding_one, zeros_acc; + int holding_zero, pend_count; + } w; +} WavpackStream; + +// flags for float_flags: + +#define FLOAT_SHIFT_ONES 1 // bits left-shifted into float = '1' +#define FLOAT_SHIFT_SAME 2 // bits left-shifted into float are the same +#define FLOAT_SHIFT_SENT 4 // bits shifted into float are sent literally +#define FLOAT_ZEROS_SENT 8 // "zeros" are not all real zeros +#define FLOAT_NEG_ZEROS 0x10 // contains negative zeros +#define FLOAT_EXCEPTIONS 0x20 // contains exceptions (inf, nan, etc.) + +/////////////////////////////// WavPack Context /////////////////////////////// + +// This internal structure holds everything required to encode or decode WavPack +// files. It is recommended that direct access to this structure be minimized +// and the provided utilities used instead. + +typedef struct { + int32_t (*read_bytes)(void *id, void *data, int32_t bcount); + uint32_t (*get_pos)(void *id); + int (*set_pos_abs)(void *id, uint32_t pos); + int (*set_pos_rel)(void *id, int32_t delta, int mode); + int (*push_back_byte)(void *id, int c); + uint32_t (*get_length)(void *id); + int (*can_seek)(void *id); +} stream_reader; + +typedef int (*blockout)(void *id, void *data, int32_t bcount); + +typedef struct { + WavpackConfig config; + + WavpackMetadata *metadata; + uint32_t metabytes; + int metacount; + + uchar *wrapper_data; + uint32_t wrapper_bytes; + + blockout blockout; + void *wv_out, *wvc_out; + + stream_reader *reader; + void *wv_in, *wvc_in; + + uint32_t filelen, file2len, filepos, file2pos, total_samples, crc_errors, first_flags; + int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, close_files; + int block_samples, max_samples, acc_samples; + M_Tag m_tag; + + int current_stream, num_streams; + WavpackStream *streams [8]; + void *stream3; + + char error_message [80]; +} WavpackContext; + +//////////////////////// function prototypes and macros ////////////////////// + +#define CLEAR(destin) memset (&destin, 0, sizeof (destin)); + +// these macros implement the weight application and update operations +// that are at the heart of the decorrelation loops + +#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10) + +#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \ + (((sample & ~0xffff) >> 9) * weight) + 1) >> 1) + +#if 1 // PERFCOND +#define apply_weight(weight, sample) (sample != (short) sample ? \ + apply_weight_f (weight, sample) : apply_weight_i (weight, sample)) +#else +#define apply_weight(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10)) +#endif + +#if 1 // PERFCOND +#define update_weight(weight, delta, source, result) \ + if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta; +#else +#define update_weight(weight, delta, source, result) \ + if (source && result) (source ^ result) < 0 ? (weight -= delta) : (weight += delta); +#endif + +#define update_weight_d1(weight, delta, source, result) \ + if (source && result) weight -= (((source ^ result) >> 30) & 2) - 1; + +#define update_weight_d2(weight, delta, source, result) \ + if (source && result) weight -= (((source ^ result) >> 29) & 4) - 2; + +#define update_weight_clip(weight, delta, source, result) \ + if (source && result && ((source ^ result) < 0 ? (weight -= delta) < -1024 : (weight += delta) > 1024)) \ + weight = weight < 0 ? -1024 : 1024; + +#define update_weight_clip_d1(weight, delta, source, result) \ + if (source && result && abs (weight -= (((source ^ result) >> 30) & 2) - 1) > 1024) \ + weight = weight < 0 ? -1024 : 1024; + +#define update_weight_clip_d2(weight, delta, source, result) \ + if (source && result && abs (weight -= (((source ^ result) >> 29) & 4) - 2) > 1024) \ + weight = weight < 0 ? -1024 : 1024; + +// bits.c + +void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end); +void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end); +uint32_t bs_close_read (Bitstream *bs); +uint32_t bs_close_write (Bitstream *bs); + +int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead); +int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten); +uint32_t DoGetFileSize (FILE *hFile), DoGetFilePosition (FILE *hFile); +int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode); +int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos); +int DoUngetc (int c, FILE *hFile), DoDeleteFile (char *filename); +int DoCloseHandle (FILE *hFile), DoTruncateFile (FILE *hFile); + +#define bs_is_open(bs) ((bs)->ptr != NULL) + +#define getbit(bs) ( \ + (((bs)->bc) ? \ + ((bs)->bc--, (bs)->sr & 1) : \ + (((++((bs)->ptr) != (bs)->end) ? (void) 0 : (bs)->wrap (bs)), (bs)->bc = 7, ((bs)->sr = *((bs)->ptr)) & 1) \ + ) ? \ + ((bs)->sr >>= 1, 1) : \ + ((bs)->sr >>= 1, 0) \ +) + +#define getbits(value, nbits, bs) { \ + while ((nbits) > (bs)->bc) { \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + (bs)->sr |= (int32_t)*((bs)->ptr) << (bs)->bc; \ + (bs)->bc += 8; \ + } \ + *(value) = (bs)->sr; \ + (bs)->sr >>= (nbits); \ + (bs)->bc -= (nbits); \ +} + +#define putbit(bit, bs) { if (bit) (bs)->sr |= (1 << (bs)->bc); \ + if (++((bs)->bc) == 8) { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr = (bs)->bc = 0; \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + }} + +#define putbit_0(bs) { \ + if (++((bs)->bc) == 8) { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr = (bs)->bc = 0; \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + }} + +#define putbit_1(bs) { (bs)->sr |= (1 << (bs)->bc); \ + if (++((bs)->bc) == 8) { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr = (bs)->bc = 0; \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + }} + +#define putbits(value, nbits, bs) { \ + (bs)->sr |= (int32_t)(value) << (bs)->bc; \ + if (((bs)->bc += (nbits)) >= 8) \ + do { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr >>= 8; \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + } while (((bs)->bc -= 8) >= 8); \ +} + +void little_endian_to_native (void *data, char *format); +void native_to_little_endian (void *data, char *format); + +// pack.c + +void pack_init (WavpackContext *wpc); +int pack_block (WavpackContext *wpc, int32_t *buffer); +double pack_noise (WavpackContext *wpc, double *peak); + +// unpack.c + +int unpack_init (WavpackContext *wpc); +int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); +int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); +int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); +int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd); +int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd); +int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd); +int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd); +int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd); +int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd); +int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd); +int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd); +int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd); +int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); +int check_crc_error (WavpackContext *wpc); + +// unpack3.c + +WavpackContext *open_file3 (WavpackContext *wpc, char *error); +int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); +int seek_sample3 (WavpackContext *wpc, uint32_t desired_index); +uint32_t get_sample_index3 (WavpackContext *wpc); +void free_stream3 (WavpackContext *wpc); +int get_version3 (WavpackContext *wpc); + +// utils.c + +int copy_timestamp (const char *src_filename, const char *dst_filename); +char *filespec_ext (char *filespec), *filespec_path (char *filespec); +char *filespec_name (char *filespec), *filespec_wild (char *filespec); +void error_line (char *error, ...), finish_line (void); +void setup_break (void); +int check_break (void); +char yna (void); +void AnsiToUTF8 (char *string, int len); + +#define FN_FIT(fn) ((strlen (fn) > 30) ? filespec_name (fn) : fn) + +// metadata.c stuff + +int read_metadata_buff (WavpackMetadata *wpmd, uchar *blockbuff, uchar **buffptr); +int write_metadata_block (WavpackContext *wpc); +int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end); +int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, uchar id); +int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd); +void free_metadata (WavpackMetadata *wpmd); + +// words.c stuff + +void init_words (WavpackStream *wps); +void word_set_bitrate (WavpackStream *wps); +void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd); +void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd); +int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd); +int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd); +int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan); +void FASTCALL send_word_lossless (WavpackStream *wps, int32_t value, int chan); +int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction); +int32_t FASTCALL get_word_lossless (WavpackStream *wps, int chan); +void flush_word (WavpackStream *wps); +int32_t nosend_word (WavpackStream *wps, int32_t value, int chan); +void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir); + +int log2s (int32_t value); +int32_t exp2s (int log); +uint32_t log2buffer (int32_t *samples, uint32_t num_samples); + +char store_weight (int weight); +int restore_weight (char weight); + +#define WORD_EOF (1L << 31) + +// float.c + +void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd); +int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values); +void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values); +int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd); +void float_values (WavpackStream *wps, int32_t *values, int32_t num_values); +void float_normalize (int32_t *values, int32_t num_values, int delta_exp); + +// analyze?.c + +void analyze_stereo (WavpackContext *wpc, int32_t *samples); +void analyze_mono (WavpackContext *wpc, int32_t *samples); + +// wputils.c + +WavpackContext *WavpackOpenFileInputEx (stream_reader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset); +WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset); + +#define OPEN_WVC 0x1 // open/read "correction" file +#define OPEN_TAGS 0x2 // read ID3v1 / APEv2 tags (seekable file) +#define OPEN_WRAPPER 0x4 // make audio wrapper available (i.e. RIFF) +#define OPEN_2CH_MAX 0x8 // open multichannel as stereo (no downmix) +#define OPEN_NORMALIZE 0x10 // normalize floating point data to +/- 1.0 +#define OPEN_STREAMING 0x20 // "streaming" mode blindly unpacks blocks + // w/o regard to header file position info + +int WavpackGetMode (WavpackContext *wpc); + +#define MODE_WVC 0x1 +#define MODE_LOSSLESS 0x2 +#define MODE_HYBRID 0x4 +#define MODE_FLOAT 0x8 +#define MODE_VALID_TAG 0x10 +#define MODE_HIGH 0x20 +#define MODE_FAST 0x40 +#define MODE_EXTRA 0x80 +#define MODE_APETAG 0x100 +#define MODE_SFX 0x200 + +int WavpackGetVersion (WavpackContext *wpc); +uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); +uint32_t WavpackGetNumSamples (WavpackContext *wpc); +uint32_t WavpackGetSampleIndex (WavpackContext *wpc); +int WavpackGetNumErrors (WavpackContext *wpc); +int WavpackLossyBlocks (WavpackContext *wpc); +int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); +WavpackContext *WavpackCloseFile (WavpackContext *wpc); +uint32_t WavpackGetSampleRate (WavpackContext *wpc); +int WavpackGetBitsPerSample (WavpackContext *wpc); +int WavpackGetBytesPerSample (WavpackContext *wpc); +int WavpackGetNumChannels (WavpackContext *wpc); +int WavpackGetReducedChannels (WavpackContext *wpc); +int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); +uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); +uchar *WavpackGetWrapperData (WavpackContext *wpc); +void WavpackFreeWrapper (WavpackContext *wpc); +double WavpackGetProgress (WavpackContext *wpc); +uint32_t WavpackGetFileSize (WavpackContext *wpc); +double WavpackGetRatio (WavpackContext *wpc); +double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); +double WavpackGetInstantBitrate (WavpackContext *wpc); +int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size); +int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value); +int WavpackWriteTag (WavpackContext *wpc); + +WavpackContext *WavpackOpenFileOutput (blockout blockout, void *wv_id, void *wvc_id); +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); +int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); +int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]); +int WavpackPackInit (WavpackContext *wpc); +int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); +int WavpackFlushSamples (WavpackContext *wpc); +void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); +void *WavpackGetWrapperLocation (void *first_block); + +#endif diff --git a/Libraries/WavPack/Files/wavpack.pc.in b/Libraries/WavPack/Files/wavpack.pc.in new file mode 100644 index 000000000..553127ed7 --- /dev/null +++ b/Libraries/WavPack/Files/wavpack.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: wavpack +Description: wavpack library +Version: @PACKAGE_VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lwavpack @ICONV@ +Cflags: -I${includedir} -DPACK -DUNPACK -DUSE_FSTREAMS -DTAGS -DSEEKING -DVER3 diff --git a/Libraries/WavPack/Files/words.c b/Libraries/WavPack/Files/words.c new file mode 100644 index 000000000..4b8fde6c3 --- /dev/null +++ b/Libraries/WavPack/Files/words.c @@ -0,0 +1,1437 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +//////////////////////////////////////////////////////////////////////////// + +// words.c + +// This module provides entropy word encoding and decoding functions using +// a variation on the Rice method. This was introduced in version 3.93 +// because it allows splitting the data into a "lossy" stream and a +// "correction" stream in a very efficient manner and is therefore ideal +// for the "hybrid" mode. For 4.0, the efficiency of this method was +// significantly improved by moving away from the normal Rice restriction of +// using powers of two for the modulus divisions and now the method can be +// used for both hybrid and pure lossless encoding. + +// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%), +// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the +// previous. Using standard Rice coding on this data would result in 1.4 +// bits per sample average (not counting sign bit). However, there is a +// very simple encoding that is over 99% efficient with this data and +// results in about 1.22 bits per sample. + +#include "wavpack.h" + +#include +#include + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +// #define DEBUG_WORDS // debug module by sending all 32 bits literally + +//////////////////////////////// local macros ///////////////////////////////// + +#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data + +// these control the time constant "slow_level" which is used for hybrid mode +// that controls bitrate as a function of residual level (HYBRID_BITRATE). +#define SLS 8 +#define SLO ((1 << (SLS - 1))) + +// these control the time constant of the 3 median level breakpoints +#define DIV0 128 // 5/7 of samples +#define DIV1 64 // 10/49 of samples +#define DIV2 32 // 20/343 of samples + +// this macro retrieves the specified median breakpoint (without frac; min = 1) +#define GET_MED(med) (((wps->w.median [med] [chan]) >> 4) + 1) + +// These macros update the specified median breakpoints. Note that the median +// is incremented when the sample is higher than the median, else decremented. +// They are designed so that the median will never drop below 1 and the value +// is essentially stationary if there are 2 increments for every 5 decrements. + +#define INC_MED0() (wps->w.median [0] [chan] += ((wps->w.median [0] [chan] + DIV0) / DIV0) * 5) +#define DEC_MED0() (wps->w.median [0] [chan] -= ((wps->w.median [0] [chan] + (DIV0-2)) / DIV0) * 2) +#define INC_MED1() (wps->w.median [1] [chan] += ((wps->w.median [1] [chan] + DIV1) / DIV1) * 5) +#define DEC_MED1() (wps->w.median [1] [chan] -= ((wps->w.median [1] [chan] + (DIV1-2)) / DIV1) * 2) +#define INC_MED2() (wps->w.median [2] [chan] += ((wps->w.median [2] [chan] + DIV2) / DIV2) * 5) +#define DEC_MED2() (wps->w.median [2] [chan] -= ((wps->w.median [2] [chan] + (DIV2-2)) / DIV2) * 2) + +#define count_bits(av) ( \ + (av) < (1 << 8) ? nbits_table [av] : \ + ( \ + (av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \ + ((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \ + ) \ +) + +///////////////////////////// local table storage //////////////////////////// + +const uint32_t bitset [] = { + 1L << 0, 1L << 1, 1L << 2, 1L << 3, + 1L << 4, 1L << 5, 1L << 6, 1L << 7, + 1L << 8, 1L << 9, 1L << 10, 1L << 11, + 1L << 12, 1L << 13, 1L << 14, 1L << 15, + 1L << 16, 1L << 17, 1L << 18, 1L << 19, + 1L << 20, 1L << 21, 1L << 22, 1L << 23, + 1L << 24, 1L << 25, 1L << 26, 1L << 27, + 1L << 28, 1L << 29, 1L << 30, 1L << 31 +}; + +const uint32_t bitmask [] = { + (1L << 0) - 1, (1L << 1) - 1, (1L << 2) - 1, (1L << 3) - 1, + (1L << 4) - 1, (1L << 5) - 1, (1L << 6) - 1, (1L << 7) - 1, + (1L << 8) - 1, (1L << 9) - 1, (1L << 10) - 1, (1L << 11) - 1, + (1L << 12) - 1, (1L << 13) - 1, (1L << 14) - 1, (1L << 15) - 1, + (1L << 16) - 1, (1L << 17) - 1, (1L << 18) - 1, (1L << 19) - 1, + (1L << 20) - 1, (1L << 21) - 1, (1L << 22) - 1, (1L << 23) - 1, + (1L << 24) - 1, (1L << 25) - 1, (1L << 26) - 1, (1L << 27) - 1, + (1L << 28) - 1, (1L << 29) - 1, (1L << 30) - 1, 0x7fffffff +}; + +const char nbits_table [] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 32 - 47 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 48 - 63 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 64 - 79 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 80 - 95 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 - 111 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 112 - 127 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 128 - 143 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 144 - 159 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 - 175 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 176 - 191 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 - 207 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 208 - 223 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 - 239 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 // 240 - 255 +}; + +static const uchar log2_table [] = { + 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15, + 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, + 0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51, + 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, + 0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0, + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce, + 0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7, + 0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff +}; + +static const uchar exp2_table [] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16, + 0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d, + 0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, + 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, + 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, + 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4, + 0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9, + 0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff +}; + +static const char ones_count_table [] = { + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 +}; + +///////////////////////////// executable code //////////////////////////////// + +static int FASTCALL mylog2 (uint32_t avalue); + +// Initialize entropy encoder for the specified stream. In lossless mode there +// are no parameters to select; in hybrid mode the bitrate mode and value need +// be initialized. + +#ifdef PACK + +void init_words (WavpackStream *wps) +{ + CLEAR (wps->w); + + if (wps->wphdr.flags & HYBRID_FLAG) + word_set_bitrate (wps); +} + +// Set up parameters for hybrid mode based on header flags and "bits" field. +// This is currently only set up for the HYBRID_BITRATE mode in which the +// allowed error varies with the residual level (from "slow_level"). The +// simpler mode (which is not used yet) has the error level directly +// controlled from the metadata. + +void word_set_bitrate (WavpackStream *wps) +{ + int bitrate_0, bitrate_1; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + + if (wps->wphdr.flags & HYBRID_BALANCE) + bitrate_1 = (wps->wphdr.flags & JOINT_STEREO) ? 256 : 0; + else { + bitrate_1 = bitrate_0; + + if (wps->wphdr.flags & JOINT_STEREO) { + if (bitrate_0 < 128) { + bitrate_1 += bitrate_0; + bitrate_0 = 0; + } + else { + bitrate_0 -= 128; + bitrate_1 += 128; + } + } + } + } + } + else + bitrate_0 = bitrate_1 = 0; + + wps->w.bitrate_acc [0] = (int32_t) bitrate_0 << 16; + wps->w.bitrate_acc [1] = (int32_t) bitrate_1 << 16; +} + +// Allocates the correct space in the metadata structure and writes the +// current median values to it. Values are converted from 32-bit unsigned +// to our internal 16-bit mylog2 values, and read_entropy_vars () is called +// to read the values back because we must compensate for the loss through +// the log function. + +void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *byteptr; + int temp; + + byteptr = wpmd->data = malloc (12); + wpmd->id = ID_ENTROPY_VARS; + + *byteptr++ = temp = mylog2 (wps->w.median [0] [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [1] [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [2] [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + *byteptr++ = temp = mylog2 (wps->w.median [0] [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [1] [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [2] [1]); + *byteptr++ = temp >> 8; + } + + wpmd->byte_length = byteptr - (uchar *) wpmd->data; + read_entropy_vars (wps, wpmd); +} + +// Allocates enough space in the metadata structure and writes the current +// high word of the bitrate accumulator and the slow_level values to it. The +// slow_level values are converted from 32-bit unsigned to our internal 16-bit +// mylog2 values. Afterward, read_entropy_vars () is called to read the values +// back because we must compensate for the loss through the log function and +// the truncation of the bitrate. + +void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *byteptr; + int temp; + + word_set_bitrate (wps); + byteptr = wpmd->data = malloc (512); + wpmd->id = ID_HYBRID_PROFILE; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + *byteptr++ = temp = log2s (wps->w.slow_level [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + *byteptr++ = temp = log2s (wps->w.slow_level [1]); + *byteptr++ = temp >> 8; + } + } + + *byteptr++ = temp = wps->w.bitrate_acc [0] >> 16; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + *byteptr++ = temp = wps->w.bitrate_acc [1] >> 16; + *byteptr++ = temp >> 8; + } + + if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) { + *byteptr++ = temp = log2s (wps->w.bitrate_delta [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + *byteptr++ = temp = log2s (wps->w.bitrate_delta [1]); + *byteptr++ = temp >> 8; + } + } + + wpmd->byte_length = byteptr - (uchar *) wpmd->data; + read_hybrid_profile (wps, wpmd); +} + +#endif + +// Read the median log2 values from the specifed metadata structure, convert +// them back to 32-bit unsigned values and store them. If length is not +// exactly correct then we flag and return an error. + +int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *byteptr = wpmd->data; + + if (wpmd->byte_length != ((wps->wphdr.flags & MONO_FLAG) ? 6 : 12)) + return FALSE; + + wps->w.median [0] [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); + wps->w.median [1] [0] = exp2s (byteptr [2] + (byteptr [3] << 8)); + wps->w.median [2] [0] = exp2s (byteptr [4] + (byteptr [5] << 8)); + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->w.median [0] [1] = exp2s (byteptr [6] + (byteptr [7] << 8)); + wps->w.median [1] [1] = exp2s (byteptr [8] + (byteptr [9] << 8)); + wps->w.median [2] [1] = exp2s (byteptr [10] + (byteptr [11] << 8)); + } + + return TRUE; +} + +// Read the hybrid related values from the specifed metadata structure, convert +// them back to their internal formats and store them. The extended profile +// stuff is not implemented yet, so return an error if we get more data than +// we know what to do with. + +int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *byteptr = wpmd->data; + uchar *endptr = byteptr + wpmd->byte_length; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.slow_level [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->w.slow_level [1] = exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; + } + } + + wps->w.bitrate_acc [0] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->w.bitrate_acc [1] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; + byteptr += 2; + } + + if (byteptr < endptr) { + wps->w.bitrate_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->w.bitrate_delta [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + + if (byteptr < endptr) + return FALSE; + } + else + wps->w.bitrate_delta [0] = wps->w.bitrate_delta [1] = 0; + + return TRUE; +} + +// This function is called during both encoding and decoding of hybrid data to +// update the "error_limit" variable which determines the maximum sample error +// allowed in the main bitstream. In the HYBRID_BITRATE mode (which is the only +// currently implemented) this is calculated from the slow_level values and the +// bitrate accumulators. Note that the bitrate accumulators can be changing. + +static void update_error_limit (WavpackStream *wps) +{ + int bitrate_0 = (wps->w.bitrate_acc [0] += wps->w.bitrate_delta [0]) >> 16; + + if (wps->wphdr.flags & MONO_FLAG) { + if (wps->wphdr.flags & HYBRID_BITRATE) { + int slow_log_0 = (wps->w.slow_level [0] + SLO) >> SLS; + + if (slow_log_0 - bitrate_0 > -0x100) + wps->w.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100); + else + wps->w.error_limit [0] = 0; + } + else + wps->w.error_limit [0] = exp2s (bitrate_0); + } + else { + int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + int slow_log_0 = (wps->w.slow_level [0] + SLO) >> SLS; + int slow_log_1 = (wps->w.slow_level [1] + SLO) >> SLS; + + if (wps->wphdr.flags & HYBRID_BALANCE) { + int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1; + + if (balance > bitrate_0) { + bitrate_1 = bitrate_0 * 2; + bitrate_0 = 0; + } + else if (-balance > bitrate_0) { + bitrate_0 = bitrate_0 * 2; + bitrate_1 = 0; + } + else { + bitrate_1 = bitrate_0 + balance; + bitrate_0 = bitrate_0 - balance; + } + } + + if (slow_log_0 - bitrate_0 > -0x100) + wps->w.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100); + else + wps->w.error_limit [0] = 0; + + if (slow_log_1 - bitrate_1 > -0x100) + wps->w.error_limit [1] = exp2s (slow_log_1 - bitrate_1 + 0x100); + else + wps->w.error_limit [1] = 0; + } + else { + wps->w.error_limit [0] = exp2s (bitrate_0); + wps->w.error_limit [1] = exp2s (bitrate_1); + } + } +} + +#ifdef PACK + +// This function writes the specified word to the open bitstream "wvbits" and, +// if the bitstream "wvcbits" is open, writes any correction data there. This +// function will work for either lossless or hybrid but because a version +// optimized for lossless exits below, it would normally be used for the hybrid +// mode only. The return value is the actual value stored to the stream (even +// if a correction file is being created) and is used as feedback to the +// predictor. + +int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan) +{ + uint32_t ones_count, low, mid, high; + int sign = (value < 0) ? 1 : 0; + +#ifdef DEBUG_WORDS + mid = value; + ones_count = 32; + while (ones_count--) { + putbit (value & 1, &wps->wvbits); + value >>= 1; + } + return mid; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !(wps->w.median [0] [1] & ~1)) { + if (wps->w.zeros_acc) { + if (value) + flush_word (wps); + else { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.zeros_acc++; + return 0; + } + } + else if (value) { + putbit_0 (&wps->wvbits); + } + else { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + CLEAR (wps->w.median); + wps->w.zeros_acc = 1; + return 0; + } + } + + if (sign) + value = ~value; + + if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) + update_error_limit (wps); + + if (value < GET_MED (0)) { + ones_count = low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + ones_count = 1; + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + ones_count = 2; + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + ones_count = 2 + (value - low) / GET_MED (2); + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + mid = (high + low + 1) >> 1; + + if (wps->w.holding_zero) { + if (ones_count) + wps->w.holding_one++; + + flush_word (wps); + + if (ones_count) { + wps->w.holding_zero = 1; + ones_count--; + } + else + wps->w.holding_zero = 0; + } + else + wps->w.holding_zero = 1; + + wps->w.holding_one = ones_count * 2; + + if (!wps->w.error_limit [chan]) { + if (high != low) { + uint32_t maxcode = high - low, code = value - low; + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1; + + if (code < extras) { + wps->w.pend_data |= code << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + } + else { + wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; + } + } + + mid = value; + } + else + while (high - low > wps->w.error_limit [chan]) + if (value < mid) { + mid = ((high = mid - 1) + low + 1) >> 1; + wps->w.pend_count++; + } + else { + mid = (high + (low = mid) + 1) >> 1; + wps->w.pend_data |= bitset [wps->w.pend_count++]; + } + + wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++); + + if (!wps->w.holding_zero) + flush_word (wps); + + if (bs_is_open (&wps->wvcbits) && wps->w.error_limit [chan]) { + uint32_t code = value - low, maxcode = high - low; + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1; + + if (bitcount) { + if (code < extras) { + putbits (code, bitcount - 1, &wps->wvcbits); + } + else { + putbits ((code + extras) >> 1, bitcount - 1, &wps->wvcbits); + putbit ((code + extras) & 1, &wps->wvcbits); + } + } + } + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.slow_level [chan] += mylog2 (mid); + } + + return sign ? ~mid : mid; +} + +// This function is an optimized version of send_word() that only handles +// lossless (error_limit == 0). It does not return a value because it always +// encodes the exact value passed. + +void FASTCALL send_word_lossless (WavpackStream *wps, int32_t value, int chan) +{ + int sign = (value < 0) ? 1 : 0; + uint32_t ones_count, low, high; + +#ifdef DEBUG_WORDS + ones_count = 32; + while (ones_count--) { + putbit (value & 1, &wps->wvbits); + value >>= 1; + } + return; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !(wps->w.median [0] [1] & ~1)) { + if (wps->w.zeros_acc) { + if (value) + flush_word (wps); + else { + wps->w.zeros_acc++; + return; + } + } + else if (value) { + putbit_0 (&wps->wvbits); + } + else { + CLEAR (wps->w.median); + wps->w.zeros_acc = 1; + return; + } + } + + if (sign) + value = ~value; + + if (value < GET_MED (0)) { + ones_count = low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + ones_count = 1; + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + ones_count = 2; + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + ones_count = 2 + (value - low) / GET_MED (2); + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + if (wps->w.holding_zero) { + if (ones_count) + wps->w.holding_one++; + + flush_word (wps); + + if (ones_count) { + wps->w.holding_zero = 1; + ones_count--; + } + else + wps->w.holding_zero = 0; + } + else + wps->w.holding_zero = 1; + + wps->w.holding_one = ones_count * 2; + + if (high != low) { + uint32_t maxcode = high - low, code = value - low; + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1; + + if (code < extras) { + wps->w.pend_data |= code << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + } + else { + wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; + } + } + + wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++); + + if (!wps->w.holding_zero) + flush_word (wps); +} + +// Used by send_word() and send_word_lossless() to actually send most the +// accumulated data onto the bitstream. This is also called directly from +// clients when all words have been sent. + +void flush_word (WavpackStream *wps) +{ + if (wps->w.zeros_acc) { + int cbits = count_bits (wps->w.zeros_acc); + + while (cbits--) { + putbit_1 (&wps->wvbits); + } + + putbit_0 (&wps->wvbits); + + while (wps->w.zeros_acc > 1) { + putbit (wps->w.zeros_acc & 1, &wps->wvbits); + wps->w.zeros_acc >>= 1; + } + + wps->w.zeros_acc = 0; + } + + if (wps->w.holding_one) { +#ifdef LIMIT_ONES + if (wps->w.holding_one >= LIMIT_ONES) { + int cbits; + + putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits); + wps->w.holding_one -= LIMIT_ONES; + cbits = count_bits (wps->w.holding_one); + + while (cbits--) { + putbit_1 (&wps->wvbits); + } + + putbit_0 (&wps->wvbits); + + while (wps->w.holding_one > 1) { + putbit (wps->w.holding_one & 1, &wps->wvbits); + wps->w.holding_one >>= 1; + } + + wps->w.holding_zero = 0; + } + else + putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits); + + wps->w.holding_one = 0; +#else + do { + putbit_1 (&wps->wvbits); + } while (--wps->w.holding_one); +#endif + } + + if (wps->w.holding_zero) { + putbit_0 (&wps->wvbits); + wps->w.holding_zero = 0; + } + + if (wps->w.pend_count) { + + while (wps->w.pend_count > 24) { + putbit (wps->w.pend_data & 1, &wps->wvbits); + wps->w.pend_data >>= 1; + wps->w.pend_count--; + } + + putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits); + wps->w.pend_data = wps->w.pend_count = 0; + } +} + +// This function is similar to send_word() except that no data is actually +// written to any stream, but it does return the value that would have been +// sent to a hybrid stream. It is used to determine beforehand how much noise +// will be added to samples. + +int32_t nosend_word (WavpackStream *wps, int32_t value, int chan) +{ + uint32_t ones_count, low, mid, high; + int sign = (value < 0) ? 1 : 0; + + if (sign) + value = ~value; + + if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) + update_error_limit (wps); + + if (value < GET_MED (0)) { + low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + ones_count = 2 + (value - low) / GET_MED (2); + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + mid = (high + low + 1) >> 1; + + if (!wps->w.error_limit [chan]) + mid = value; + else + while (high - low > wps->w.error_limit [chan]) + if (value < mid) + mid = ((high = mid - 1) + low + 1) >> 1; + else + mid = (high + (low = mid) + 1) >> 1; + + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.slow_level [chan] += mylog2 (mid); + + return sign ? ~mid : mid; +} + +// This function is used to scan some number of samples to set the variables +// "slow_level" and the "median" array. In pure symetrical encoding mode this +// would not be needed because these values would simply be continued from the +// previous block. However, in the -X modes and the 32-bit modes we cannot do +// this because parameters may change between blocks and the variables might +// not apply. This function can work in mono or stereo and can scan a block +// in either direction. + +void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir) +{ + uint32_t flags = wps->wphdr.flags, value, low; + int chan; + + CLEAR (wps->w.slow_level); + CLEAR (wps->w.median); + + if (flags & MONO_FLAG) { + if (dir < 0) { + samples += (num_samples - 1); + dir = -1; + } + else + dir = 1; + } + else { + if (dir < 0) { + samples += (num_samples - 1) * 2; + dir = -2; + } + else + dir = 2; + } + + while (num_samples--) { + + value = labs (samples [chan = 0]); + + if (flags & HYBRID_BITRATE) { + wps->w.slow_level [0] -= (wps->w.slow_level [0] + SLO) >> SLS; + wps->w.slow_level [0] += mylog2 (value); + } + + if (value < GET_MED (0)) { + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + DEC_MED2 (); + } + else { + INC_MED2 (); + } + } + } + + if (!(flags & MONO_FLAG)) { + value = labs (samples [chan = 1]); + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.slow_level [1] -= (wps->w.slow_level [1] + SLO) >> SLS; + wps->w.slow_level [1] += mylog2 (value); + } + + if (value < GET_MED (0)) { + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + DEC_MED2 (); + } + else { + INC_MED2 (); + } + } + } + } + + samples += dir; + } +} + +#endif + +#ifdef UNPACK + +static uint32_t FASTCALL read_code (Bitstream *bs, uint32_t maxcode); + +// Read the next word from the bitstream "wvbits" and return the value. This +// function can be used for hybrid or lossless streams, but since an +// optimized version is available for lossless this function would normally +// be used for hybrid only. If a hybrid lossless stream is being read then +// the "correction" offset is written at the specified pointer. A return value +// of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or +// some other error occurred. + +int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction) +{ + uint32_t ones_count, low, mid, high; + int next8, sign; + int32_t value; + + if (correction) + *correction = 0; + +#ifdef DEBUG_WORDS + ones_count = 32; + while (ones_count--) + value = getbit (&wps->wvbits) ? (value >> 1) | 0x80000000 : (value >> 1) & 0x7fffffff; + return value; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.median [0] [1] & ~1)) { + uint32_t mask; + int cbits; + + if (wps->w.zeros_acc) { + if (--wps->w.zeros_acc) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + return 0; + } + } + else { + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + wps->w.zeros_acc = cbits; + else { + for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + wps->w.zeros_acc |= mask; + + wps->w.zeros_acc |= mask; + } + + if (wps->w.zeros_acc) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + CLEAR (wps->w.median); + return 0; + } + } + } + + if (wps->w.holding_zero) + ones_count = wps->w.holding_zero = 0; + else { + if (wps->wvbits.bc < 8) { + if (++(wps->wvbits.ptr) == wps->wvbits.end) + wps->wvbits.wrap (&wps->wvbits); + + next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff; + wps->wvbits.bc += 8; + } + else + next8 = wps->wvbits.sr & 0xff; + + if (next8 == 0xff) { + wps->wvbits.bc -= 8; + wps->wvbits.sr >>= 8; + + for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == (LIMIT_ONES + 1)) + return WORD_EOF; + + if (ones_count == LIMIT_ONES) { + uint32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } + } + else { + wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1; + wps->wvbits.sr >>= ones_count + 1; + } + + if (wps->w.holding_one) { + wps->w.holding_one = ones_count & 1; + ones_count = (ones_count >> 1) + 1; + } + else { + wps->w.holding_one = ones_count & 1; + ones_count >>= 1; + } + + wps->w.holding_zero = ~wps->w.holding_one & 1; + } + + if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) + update_error_limit (wps); + + if (ones_count == 0) { + low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (ones_count == 1) { + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (ones_count == 2) { + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + mid = (high + low + 1) >> 1; + + if (!wps->w.error_limit [chan]) + mid = read_code (&wps->wvbits, high - low) + low; + else while (high - low > wps->w.error_limit [chan]) { + if (getbit (&wps->wvbits)) + mid = (high + (low = mid) + 1) >> 1; + else + mid = ((high = mid - 1) + low + 1) >> 1; + } + + sign = getbit (&wps->wvbits); + + if (bs_is_open (&wps->wvcbits) && wps->w.error_limit [chan]) { + value = read_code (&wps->wvcbits, high - low) + low; + + if (correction) + *correction = sign ? (mid - value) : (value - mid); + } + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.slow_level [chan] += mylog2 (mid); + } + + return sign ? ~mid : mid; +} + +// This is an optimized version of get_word() that is used for lossless only +// (error_limit == 0). There are two versions of an internal section; they +// are identical from a functional standpoint, but one may be faster than the +// other under different compilers / processors. + +int32_t FASTCALL get_word_lossless (WavpackStream *wps, int chan) +{ + uint32_t ones_count, low, high; + int next8; + +#ifdef DEBUG_WORDS + ones_count = 32; + while (ones_count--) + low = getbit (&wps->wvbits) ? (low >> 1) | 0x80000000 : (low >> 1) & 0x7fffffff; + return low; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.median [0] [1] & ~1)) { + uint32_t mask; + int cbits; + + if (wps->w.zeros_acc) { + if (--wps->w.zeros_acc) + return 0; + } + else { + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + wps->w.zeros_acc = cbits; + else { + for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + wps->w.zeros_acc |= mask; + + wps->w.zeros_acc |= mask; + } + + if (wps->w.zeros_acc) { + CLEAR (wps->w.median); + return 0; + } + } + } + + if (wps->w.holding_zero) + ones_count = wps->w.holding_zero = 0; + else { + if (wps->wvbits.bc < 8) { + if (++(wps->wvbits.ptr) == wps->wvbits.end) + wps->wvbits.wrap (&wps->wvbits); + + next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff; + wps->wvbits.bc += 8; + } + else + next8 = wps->wvbits.sr & 0xff; + + if (next8 == 0xff) { + wps->wvbits.bc -= 8; + wps->wvbits.sr >>= 8; + + for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == (LIMIT_ONES + 1)) + return WORD_EOF; + + if (ones_count == LIMIT_ONES) { + uint32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } + } + else { + wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1; + wps->wvbits.sr >>= ones_count + 1; + } + + if (wps->w.holding_one) { + wps->w.holding_one = ones_count & 1; + ones_count = (ones_count >> 1) + 1; + } + else { + wps->w.holding_one = ones_count & 1; + ones_count >>= 1; + } + + wps->w.holding_zero = ~wps->w.holding_one & 1; + } + + if (ones_count == 0) { + low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (ones_count == 1) { + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (ones_count == 2) { + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + low += read_code (&wps->wvbits, high - low); + return (getbit (&wps->wvbits)) ? ~low : low; +} + +// Read a single unsigned value from the specified bitstream with a value +// from 0 to maxcode. If there are exactly a power of two number of possible +// codes then this will read a fixed number of bits; otherwise it reads the +// minimum number of bits and then determines whether another bit is needed +// to define the code. + +static uint32_t FASTCALL read_code (Bitstream *bs, uint32_t maxcode) +{ + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1, code; + + if (!bitcount) + return 0; + + getbits (&code, bitcount - 1, bs); + code &= bitmask [bitcount - 1]; + + if (code >= extras) { + code = (code << 1) - extras; + + if (getbit (bs)) + ++code; + } + + return code; +} + +#endif + +// The concept of a base 2 logarithm is used in many parts of WavPack. It is +// a way of sufficiently accurately representing 32-bit signed and unsigned +// values storing only 16 bits (actually fewer). It is also used in the hybrid +// mode for quickly comparing the relative magnitude of large values (i.e. +// division) and providing smooth exponentials using only addition. + +// These are not strict logarithms in that they become linear around zero and +// can therefore represent both zero and negative values. They have 8 bits +// of precision and in "roundtrip" conversions the total error never exceeds 1 +// part in 225 except for the cases of +/-115 and +/-195 (which error by 1). + + +// This function returns the log2 for the specified 32-bit unsigned value. +// The maximum value allowed is about 0xff800000 and returns 8447. + +static int FASTCALL mylog2 (uint32_t avalue) +{ + int dbits; + + if ((avalue += avalue >> 9) < (1 << 8)) { + dbits = nbits_table [avalue]; + return (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff]; + } + else { + if (avalue < (1L << 16)) + dbits = nbits_table [avalue >> 8] + 8; + else if (avalue < (1L << 24)) + dbits = nbits_table [avalue >> 16] + 16; + else + dbits = nbits_table [avalue >> 24] + 24; + + return (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff]; + } +} + +// This function scans a buffer of longs and accumulates the total log2 value +// of all the samples. This is useful for determining maximum compression +// because the bitstream storage required for entropy coding is proportional +// to the base 2 log of the samples. + +uint32_t log2buffer (int32_t *samples, uint32_t num_samples) +{ + uint32_t result = 0, avalue; + int dbits; + + while (num_samples--) { + avalue = abs (*samples++); + + if ((avalue += avalue >> 9) < (1 << 8)) { + dbits = nbits_table [avalue]; + result += (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff]; + } + else { + if (avalue < (1L << 16)) + dbits = nbits_table [avalue >> 8] + 8; + else if (avalue < (1L << 24)) + dbits = nbits_table [avalue >> 16] + 16; + else + dbits = nbits_table [avalue >> 24] + 24; + + result += (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff]; + } + } + + return result; +} + +// This function returns the log2 for the specified 32-bit signed value. +// All input values are valid and the return values are in the range of +// +/- 8192. + +int log2s (int32_t value) +{ + return (value < 0) ? -mylog2 (-value) : mylog2 (value); +} + +// This function returns the original integer represented by the supplied +// logarithm (at least within the provided accuracy). The log is signed, +// but since a full 32-bit value is returned this can be used for unsigned +// conversions as well (i.e. the input range is -8192 to +8447). + +int32_t exp2s (int log) +{ + uint32_t value; + + if (log < 0) + return -exp2s (-log); + + value = exp2_table [log & 0xff] | 0x100; + + if ((log >>= 8) <= 9) + return value >> (9 - log); + else + return value << (log - 9); +} + +// These two functions convert internal weights (which are normally +/-1024) +// to and from an 8-bit signed character version for storage in metadata. The +// weights are clipped here in the case that they are outside that range. + +char store_weight (int weight) +{ + if (weight > 1024) + weight = 1024; + else if (weight < -1024) + weight = -1024; + + if (weight > 0) + weight -= (weight + 64) >> 7; + + return (weight + 4) >> 3; +} + +int restore_weight (char weight) +{ + int result; + + if ((result = (int) weight << 3) > 0) + result += (result + 64) >> 7; + + return result; +} diff --git a/Libraries/WavPack/Files/wputils.c b/Libraries/WavPack/Files/wputils.c new file mode 100644 index 000000000..3c2dbbad7 --- /dev/null +++ b/Libraries/WavPack/Files/wputils.c @@ -0,0 +1,2107 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wputils.c + +// This module provides a high-level interface to reading and writing WavPack +// files. WavPack input files can be opened as standard "C" streams using a +// provided filename. However, an alternate entry uses stream-reading +// callbacks to make using another file I/O method easy. Note that in this +// case the user application is responsible for finding and opening the .wvc +// file if the use of them is desired. + +// For writing WavPack files there are no I/O routines used; a callback for +// writing completed blocks is provided. + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif + +#include "wavpack.h" + +#if !defined(WIN32) +#define stricmp(x,y) strcasecmp(x,y) +#endif + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +static void free_streams (WavpackContext *wpc); + +///////////////////////////// local table storage //////////////////////////// + +const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 }; + +///////////////////////////// executable code //////////////////////////////// + +#ifdef TAGS +static int load_tag (WavpackContext *wpc); +static int valid_tag (M_Tag *m_tag); +static void free_tag (M_Tag *m_tag); +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +static uint32_t read_next_header (stream_reader *reader, void *id, WavpackHeader *wphdr); +static uint32_t seek_final_index (stream_reader *reader, void *id); + +// This code provides an interface between the reader callback mechanism that +// WavPack uses internally and the standard fstream C library. + +#ifdef USE_FSTREAMS + +static int32_t read_bytes (void *id, void *data, int32_t bcount) +{ + return fread (data, 1, bcount, (FILE*) id); +} + +static uint32_t get_pos (void *id) +{ + return ftell ((FILE*) id); +} + +static int set_pos_abs (void *id, uint32_t pos) +{ + return fseek (id, pos, SEEK_SET); +} + +static int set_pos_rel (void *id, int32_t delta, int mode) +{ + return fseek (id, delta, mode); +} + +static int push_back_byte (void *id, int c) +{ + return ungetc (c, id); +} + +static uint32_t get_length (void *id) +{ + FILE *file = id; + struct stat statbuf; + + if (!file || fstat (fileno (file), &statbuf) || !(statbuf.st_mode & S_IFREG)) + return 0; + + return statbuf.st_size; +} + +static int can_seek (void *id) +{ + FILE *file = id; + struct stat statbuf; + + return file && !fstat (fileno (file), &statbuf) && (statbuf.st_mode & S_IFREG); +} + +static stream_reader freader = { + read_bytes, get_pos, set_pos_abs, set_pos_rel, push_back_byte, get_length, can_seek +}; + +// This function attempts to open the specified WavPack file for reading. If +// this fails for any reason then an appropriate message is copied to "error" +// and NULL is returned, otherwise a pointer to a WavpackContext structure is +// returned (which is used to call all other functions in this module). A +// filename beginning with "-" is assumed to be stdin. The "flags" argument +// has the following bit mask values to specify details of the open operation: + +// OPEN_WVC: attempt to open/read "correction" file +// OPEN_TAGS: attempt to read ID3v1 / APEv2 tags (requires seekable file) +// OPEN_WRAPPER: make audio wrapper available (i.e. RIFF) to caller +// OPEN_2CH_MAX: open only first stream of multichannel file (usually L/R) +// OPEN_NORMALIZE: normalize floating point data to +/- 1.0 (w/ offset exp) +// OPEN_STREAMING: blindly unpacks blocks w/o regard to header file position + +// Version 4.2 of the WavPack library adds the OPEN_STREAMING flag. This is +// essentially a "raw" mode where the library will simply decode any blocks +// fed it through the reader callback, regardless of where those blocks came +// from in a stream. The only requirement is that complete WavPack blocks are +// fed to the decoder (and this may require multiple blocks in multichannel +// mode) and that complete blocks are decoded (even if all samples are not +// actually required). All the blocks must contain the same number of channels +// and bit resolution, and the correction data must be either present or not. +// All other parameters may change from block to block (like lossy/lossless). +// Obviously, in this mode any seeking must be performed by the application +// (and again, decoding must start at the beginning of the block containing +// the seek sample). + +WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset) +{ + FILE *wv_id, *wvc_id; + WavpackContext *wpc; + + if (*infilename == '-') { + wv_id = stdin; +#if defined(WIN32) + setmode (fileno (stdin), O_BINARY); +#endif + } + else if ((wv_id = fopen (infilename, "rb")) == NULL) { + strcpy (error, "can't open file"); + return NULL; + } + + if (wv_id != stdin && (flags & OPEN_WVC)) { + char *in2filename = malloc (strlen (infilename) + 10); + + strcpy (in2filename, infilename); + strcat (in2filename, "c"); + wvc_id = fopen (in2filename, "rb"); + } + else + wvc_id = NULL; + + wpc = WavpackOpenFileInputEx (&freader, wv_id, wvc_id, error, flags, norm_offset); + + if (!wpc) { + if (wv_id) + fclose (wv_id); + + if (wvc_id) + fclose (wvc_id); + } + else + wpc->close_files = TRUE; + + return wpc; +} + +#endif + +// This function is identical to WavpackOpenFileInput() except that instead +// of providing a filename to open, the caller provides a pointer to a set of +// reader callbacks and instances of up to two streams. The first of these +// streams is required and contains the regular WavPack data stream; the second +// contains the "correction" file if desired. Unlike the standard open +// function which handles the correction file transparently, in this case it +// is the responsibility of the caller to be aware of correction files. + +WavpackContext *WavpackOpenFileInputEx (stream_reader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset) +{ + WavpackContext *wpc = malloc (sizeof (WavpackContext)); + WavpackStream *wps; + uchar first_byte; + uint32_t bcount; + + if (!wpc) { + strcpy (error, "can't allocate memory"); + return NULL; + } + + CLEAR (*wpc); + wpc->wv_in = wv_id; + wpc->wvc_in = wvc_id; + wpc->reader = reader; + wpc->total_samples = (uint32_t) -1; + wpc->norm_offset = norm_offset; + wpc->open_flags = flags; + + wpc->filelen = wpc->reader->get_length (wpc->wv_in); + +#ifdef TAGS + if ((flags & OPEN_TAGS) && wpc->reader->can_seek (wpc->wv_in)) { + load_tag (wpc); + wpc->reader->set_pos_abs (wpc->wv_in, 0); + } +#endif + +#ifdef VER3 + if (wpc->reader->read_bytes (wpc->wv_in, &first_byte, 1) != 1) { + strcpy (error, "can't read all of WavPack file!"); + return WavpackCloseFile (wpc); + } + + wpc->reader->push_back_byte (wpc->wv_in, first_byte); + + if (first_byte == 'R') + return open_file3 (wpc, error); +#endif + + wpc->streams [0] = wps = malloc (sizeof (WavpackStream)); + wpc->num_streams = 1; + CLEAR (*wps); + + while (!wps->wphdr.block_samples) { + + wpc->filepos = wpc->reader->get_pos (wpc->wv_in); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + strcpy (error, "not compatible with this version of WavPack file!"); + return WavpackCloseFile (wpc); + } + + wpc->filepos += bcount; + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->blockbuff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) != wps->wphdr.ckSize - 24) { + strcpy (error, "can't read all of WavPack file!"); + return WavpackCloseFile (wpc); + } + + if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { + strcpy (error, "not compatible with this version of WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wps->wphdr.block_samples && !(flags & OPEN_STREAMING)) { + if (wps->wphdr.total_samples == (uint32_t) -1 && wpc->reader->can_seek (wpc->wv_in)) { + uint32_t pos_save = wpc->reader->get_pos (wpc->wv_in); + uint32_t final_index = seek_final_index (wpc->reader, wpc->wv_in); + + if (final_index != (uint32_t) -1) + wpc->total_samples = final_index - wps->wphdr.block_index; + + wpc->reader->set_pos_abs (wpc->wv_in, pos_save); + } + else + wpc->total_samples = wps->wphdr.total_samples; + } + + if (wpc->wvc_in && wps->wphdr.block_samples && (wps->wphdr.flags & HYBRID_FLAG)) { + wpc->file2len = wpc->reader->get_length (wpc->wvc_in); + wpc->wvc_flag = TRUE; + } + + if (wpc->wvc_flag) { + wpc->file2pos = wpc->reader->get_pos (wpc->wvc_in); + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + strcpy (error, "problem with correction file"); + return WavpackCloseFile (wpc); + } + + wpc->file2pos += bcount; + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + strcpy (error, "can't read all of WavPack file!"); + return WavpackCloseFile (wpc); + } + } + + if (!unpack_init (wpc)) { + strcpy (error, wpc->error_message [0] ? wpc->error_message : + "not compatible with this version of WavPack file!"); + + return WavpackCloseFile (wpc); + } + } + + wpc->config.flags &= ~0xff; + wpc->config.flags |= wps->wphdr.flags & 0xff; + wpc->config.bytes_per_sample = (wps->wphdr.flags & BYTES_STORED) + 1; + wpc->config.float_norm_exp = wps->float_norm_exp; + + wpc->config.bits_per_sample = (wpc->config.bytes_per_sample * 8) - + ((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB); + + if (!wpc->config.sample_rate) { + if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK) + wpc->config.sample_rate = 44100; + else + wpc->config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB]; + } + + if (!wpc->config.num_channels) { + wpc->config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; + wpc->config.channel_mask = 0x5 - wpc->config.num_channels; + } + + if ((flags & OPEN_2CH_MAX) && !(wps->wphdr.flags & FINAL_BLOCK)) + wpc->reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; + + return wpc; +} + +// This function obtains general information about an open file and returns +// a mask with the following bit values: + +// MODE_WVC: a .wvc file has been found and will be used for lossless +// MODE_LOSSLESS: file is lossless (either pure or hybrid) +// MODE_HYBRID: file is hybrid mode (either lossy or lossless) +// MODE_FLOAT: audio data is 32-bit ieee floating point +// MODE_VALID_TAG: file conatins a valid ID3v1 or APEv2 tag +// MODE_HIGH: file was created in "high" mode (information only) +// MODE_FAST: file was created in "fast" mode (information only) +// MODE_EXTRA: file was created using "extra" mode (information only) +// MODE_APETAG: file contains a valid APEv2 tag +// MODE_SFX: file was created as a "self-extracting" executable + +int WavpackGetMode (WavpackContext *wpc) +{ + int mode = 0; + + if (wpc) { + if (wpc->config.flags & CONFIG_HYBRID_FLAG) + mode |= MODE_HYBRID; + else if (!(wpc->config.flags & CONFIG_LOSSY_MODE)) + mode |= MODE_LOSSLESS; + + if (wpc->wvc_flag) + mode |= (MODE_LOSSLESS | MODE_WVC); + + if (wpc->lossy_blocks) + mode &= ~MODE_LOSSLESS; + + if (wpc->config.flags & CONFIG_FLOAT_DATA) + mode |= MODE_FLOAT; + + if (wpc->config.flags & CONFIG_HIGH_FLAG) + mode |= MODE_HIGH; + + if (wpc->config.flags & CONFIG_FAST_FLAG) + mode |= MODE_FAST; + + if (wpc->config.flags & CONFIG_EXTRA_MODE) + mode |= MODE_EXTRA; + + if (wpc->config.flags & CONFIG_CREATE_EXE) + mode |= MODE_SFX; + +#ifdef TAGS + if (valid_tag (&wpc->m_tag)) { + mode |= MODE_VALID_TAG; + + if (valid_tag (&wpc->m_tag) == 'A') + mode |= MODE_APETAG; + } +#endif + } + + return mode; +} + +// This function returns the major version number of the WavPack program +// (or library) that created the open file. Currently, this can be 1 to 4. +// Minor versions are not recorded in WavPack files. + +int WavpackGetVersion (WavpackContext *wpc) +{ + if (wpc) { +#ifdef VER3 + if (wpc->stream3) + return get_version3 (wpc); +#endif + return 4; + } + + return 0; +} + +#endif + +#ifdef UNPACK + +// Unpack the specified number of samples from the current file position. +// Note that "samples" here refers to "complete" samples, which would be +// 2 longs for stereo files or even more for multichannel files, so the +// required memory at "buffer" is 4 * samples * num_channels bytes. The +// audio data is returned right-justified in 32-bit longs in the endian +// mode native to the executing processor. So, if the original data was +// 16-bit, then the values returned would be +/-32k. Floating point data +// can also be returned if the source was floating point data (and this +// can be optionally normalized to +/-1.0 by using the appropriate flag +// in the call to WavpackOpenFileInput ()). The actual number of samples +// unpacked is returned, which should be equal to the number requested unless +// the end of fle is encountered or an error occurs. + +uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream = 0]; + uint32_t bcount, samples_unpacked = 0, samples_to_unpack; + int num_channels = wpc->config.num_channels; + +#ifdef VER3 + if (wpc->stream3) + return unpack_samples3 (wpc, buffer, samples); +#endif + + while (samples) { + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || + wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) { + free_streams (wpc); + wpc->filepos = wpc->reader->get_pos (wpc->wv_in); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wpc->filepos += bcount; + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->blockbuff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + strcpy (wpc->error_message, "can't read all of WavPack file!"); + break; + } + + if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { + strcpy (wpc->error_message, "not compatible with this version of WavPack file!"); + break; + } + + if (wps->wphdr.block_samples && wpc->wvc_flag) { + wpc->file2pos = wpc->reader->get_pos (wpc->wvc_in); + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wpc->file2pos += bcount; + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) + break; + } + + if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index) + if (!unpack_init (wpc)) + break; + } + + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || + wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) + continue; + + if (wps->sample_index < wps->wphdr.block_index) { + samples_to_unpack = wps->wphdr.block_index - wps->sample_index; + + if (samples_to_unpack > samples) + samples_to_unpack = samples; + + wps->sample_index += samples_to_unpack; + samples_unpacked += samples_to_unpack; + samples -= samples_to_unpack; + + if (wpc->reduced_channels) + samples_to_unpack *= wpc->reduced_channels; + else + samples_to_unpack *= num_channels; + + while (samples_to_unpack--) + *buffer++ = 0; + + continue; + } + + samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; + + if (samples_to_unpack > samples) + samples_to_unpack = samples; + + if (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { + int32_t *temp_buffer = malloc (samples_to_unpack * 8), *src, *dst; + int offset = 0; + uint32_t samcnt; + + while (1) { + if (wpc->current_stream == wpc->num_streams) { + wps = wpc->streams [wpc->num_streams++] = malloc (sizeof (WavpackStream)); + CLEAR (*wps); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->blockbuff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + strcpy (wpc->error_message, "can't read all of WavPack file!"); + break; + } + + if (wpc->wvc_flag) { + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) + break; + } + + if (!unpack_init (wpc)) + break; + } + else + wps = wpc->streams [wpc->current_stream]; + + unpack_samples (wpc, src = temp_buffer, samples_to_unpack); + samcnt = samples_to_unpack; + dst = buffer + offset; + + if (wps->wphdr.flags & MONO_FLAG) { + while (samcnt--) { + dst [0] = *src++; + dst += num_channels; + } + + offset++; + } + else { + while (samcnt--) { + dst [0] = *src++; + dst [1] = *src++; + dst += num_channels; + } + + offset += 2; + } + + if (wps->wphdr.flags & FINAL_BLOCK) + break; + else + wpc->current_stream++; + } + + wps = wpc->streams [wpc->current_stream = 0]; + free (temp_buffer); + } + else + unpack_samples (wpc, buffer, samples_to_unpack); + + if (wpc->reduced_channels) + buffer += samples_to_unpack * wpc->reduced_channels; + else + buffer += samples_to_unpack * num_channels; + + samples_unpacked += samples_to_unpack; + samples -= samples_to_unpack; + + if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) { + if (check_crc_error (wpc) && wps->blockbuff) { + + if (wpc->reader->can_seek (wpc->wv_in)) { + int32_t rseek = ((WavpackHeader *) wps->blockbuff)->ckSize / 3; + wpc->reader->set_pos_rel (wpc->wv_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR); + } + + if (wpc->wvc_flag && wps->block2buff && wpc->reader->can_seek (wpc->wvc_in)) { + int32_t rseek = ((WavpackHeader *) wps->block2buff)->ckSize / 3; + wpc->reader->set_pos_rel (wpc->wvc_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR); + } + + wpc->crc_errors++; + } + } + + if (wps->sample_index == wpc->total_samples) + break; + } + + return samples_unpacked; +} + +#ifdef SEEKING + +static uint32_t find_sample (WavpackContext *wpc, void *infile, uint32_t header_pos, uint32_t sample); + +// Seek to the specifed sample index, returning TRUE on success. Note that +// files generated with version 4.0 or newer will seek almost immediately. +// Older files can take quite long if required to seek through unplayed +// portions of the file, but will create a seek map so that reverse seeks +// (or forward seeks to already scanned areas) will be very fast. + +int WavpackSeekSample (WavpackContext *wpc, uint32_t sample) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream = 0]; + uint32_t bcount, samples_to_skip; + int32_t *buffer; + + if (wpc->total_samples == (uint32_t) -1 || sample >= wpc->total_samples || + !wpc->reader->can_seek (wpc->wv_in) || (wpc->open_flags & OPEN_STREAMING) || + (wpc->wvc_flag && !wpc->reader->can_seek (wpc->wvc_in))) + return FALSE; + +#ifdef VER3 + if (wpc->stream3) + return seek_sample3 (wpc, sample); +#endif + + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || sample < wps->wphdr.block_index || + sample >= wps->wphdr.block_index + wps->wphdr.block_samples) { + + free_streams (wpc); + wpc->filepos = find_sample (wpc, wpc->wv_in, wpc->filepos, sample); + + if (wpc->filepos == (uint32_t) -1) + return FALSE; + + if (wpc->wvc_flag) { + wpc->file2pos = find_sample (wpc, wpc->wvc_in, 0, sample); + + if (wpc->file2pos == (uint32_t) -1) + return FALSE; + } + } + + if (!wps->blockbuff) { + wpc->reader->set_pos_abs (wpc->wv_in, wpc->filepos); + wpc->reader->read_bytes (wpc->wv_in, &wps->wphdr, sizeof (WavpackHeader)); + little_endian_to_native (&wps->wphdr, WavpackHeaderFormat); + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader)); + + if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + sizeof (WavpackHeader), wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + free_streams (wpc); + return FALSE; + } + + if (wpc->wvc_flag) { + wpc->reader->set_pos_abs (wpc->wvc_in, wpc->file2pos); + wpc->reader->read_bytes (wpc->wvc_in, &wps->wphdr, sizeof (WavpackHeader)); + little_endian_to_native (&wps->wphdr, WavpackHeaderFormat); + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader)); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + sizeof (WavpackHeader), wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + free_streams (wpc); + return FALSE; + } + } + + if (!unpack_init (wpc)) { + free_streams (wpc); + return FALSE; + } + } + + while (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { + if (++wpc->current_stream == wpc->num_streams) { + wps = wpc->streams [wpc->num_streams++] = malloc (sizeof (WavpackStream)); + CLEAR (*wps); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->blockbuff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + strcpy (wpc->error_message, "can't read all of WavPack file!"); + break; + } + + if (wpc->wvc_flag) { + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) + break; + } + + if (!unpack_init (wpc)) + break; + } + else + wps = wpc->streams [wpc->current_stream]; + } + + if (sample < wps->sample_index) + for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) + if (!unpack_init (wpc)) + return FALSE; + + samples_to_skip = sample - wps->sample_index; + + if (samples_to_skip) { + buffer = malloc (samples_to_skip * 8); + + for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) + unpack_samples (wpc, buffer, samples_to_skip); + + free (buffer); + } + + wpc->current_stream = 0; + return TRUE; +} + +#endif + +#ifdef TAGS + +// Attempt to get the specified item from the specified ID3v1 or APEv2 tag. +// The "size" parameter specifies the amount of space available at "value", +// if the desired item will not fit in this space then ellipses (...) will +// be appended and the string terminated. Only text data are supported. + +static void tagcpy (char *dest, char *src, int tag_size); + +int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size) +{ + M_Tag *m_tag = &wpc->m_tag; + char *lvalue = NULL; + + if (value) + *value = 0; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') { + char *p = m_tag->ape_tag_data; + char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr); + int i; + + for (i = 0; i < m_tag->ape_tag_hdr.item_count; ++i) { + int vsize, flags, isize; + + vsize = * (int32_t *) p; p += 4; + flags = * (int32_t *) p; p += 4; + isize = strlen (p); + + little_endian_to_native (&vsize, "L"); + little_endian_to_native (&flags, "L"); + + if (p + isize + vsize + 1 > q) + break; + + if (isize && vsize && !stricmp (item, p) && !(flags & 6)) { + + if ((lvalue = malloc (vsize + 1)) != NULL) { + strncpy (lvalue, p + isize + 1, vsize); + lvalue [vsize] = 0; + } + + break; + } + else + p += isize + vsize + 1; + } + } + else if (m_tag->id3_tag.tag_id [0] == 'T') { + if ((lvalue = malloc (128)) == NULL) + return FALSE; + + lvalue [0] = 0; + + if (!stricmp (item, "title")) + tagcpy (lvalue, m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)); + else if (!stricmp (item, "artist")) + tagcpy (lvalue, m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)); + else if (!stricmp (item, "album")) + tagcpy (lvalue, m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)); + else if (!stricmp (item, "year")) + tagcpy (lvalue, m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)); + else if (!stricmp (item, "comment")) + tagcpy (lvalue, m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.title)); + + if (!lvalue [0]) { + free (lvalue); + return FALSE; + } + } + else + return FALSE; + + if (lvalue) { + if (value && size >= 4) { + if (strlen (lvalue) >= size) { + lvalue [size - 4] = lvalue [size - 3] = lvalue [size - 2] = '.'; + lvalue [size - 1] = 0; + } + + strcpy (value, lvalue); + } + + free (lvalue); + return TRUE; + } + else + return FALSE; +} + +#endif + +#endif + +#ifdef PACK + +// Open context for writing WavPack files. The returned context pointer is used +// in all following calls to the library. The "blockout" function will be used +// to store the actual completed WavPack blocks and will be called with the id +// pointers containing user defined data (one for the wv file and one for the +// wvc file). A return value of NULL indicates that memory could not be +// allocated for the context. + +WavpackContext *WavpackOpenFileOutput (blockout blockout, void *wv_id, void *wvc_id) +{ + WavpackContext *wpc = malloc (sizeof (WavpackContext)); + + if (!wpc) + return NULL; + + CLEAR (*wpc); + wpc->blockout = blockout; + wpc->wv_out = wv_id; + wpc->wvc_out = wvc_id; + return wpc; +} + +// Set configuration for writing WavPack files. This must be done before +// sending any actual samples, however it is okay to send wrapper or other +// metadata before calling this. The "config" structure contains the following +// required information: + +// config->bytes_per_sample see WavpackGetBytesPerSample() for info +// config->bits_per_sample see WavpackGetBitsPerSample() for info +// config->channel_mask Microsoft standard (mono = 4, stereo = 3) +// config->num_channels self evident +// config->sample_rate self evident + +// In addition, the following fields and flags may be set: + +// config->flags: +// -------------- +// o CONFIG_HYBRID_FLAG select hybrid mode (must set bitrate) +// o CONFIG_JOINT_STEREO select joint stereo (must set override also) +// o CONFIG_JOINT_OVERRIDE override default joint stereo selection +// o CONFIG_HYBRID_SHAPE select hybrid noise shaping (set override & +// shaping_weight != 0.0) +// o CONFIG_SHAPE_OVERRIDE override default hybrid noise shaping +// (set CONFIG_HYBRID_SHAPE and shaping_weight) +// o CONFIG_FAST_FLAG "fast" compression mode +// o CONFIG_HIGH_FLAG "high" compression mode +// o CONFIG_BITRATE_KBPS hybrid bitrate is kbps, not bits / sample +// o CONFIG_CREATE_WVC create correction file +// o CONFIG_OPTIMIZE_WVC maximize bybrid compression (-cc option) +// o CONFIG_CALC_NOISE calc noise in hybrid mode +// o CONFIG_EXTRA_MODE extra processing mode (slow!) +// o CONFIG_SKIP_WVX no wvx stream for floats & large ints + +// config->bitrate hybrid bitrate in either bits/sample or kbps +// config->shaping_weight hybrid noise shaping coefficient override +// config->block_samples force samples per WavPack block (0 = use deflt) +// config->float_norm_exp select floating-point data (127 for +/-1.0) +// config->xmode extra mode processing value override + +// If the number of samples to be written is known then it should be passed +// here. If the duration is not known then pass -1. In the case that the size +// is not known (or the writing is terminated early) then it is suggested that +// the application retrieve the first block written and let the library update +// the total samples indication. A function is provided to do this update and +// it should be done to the "correction" file also. If this cannot be done +// (because a pipe is being used, for instance) then a valid WavPack will still +// be created, but when applications want to access that file they will have +// to seek all the way to the end to determine the actual duration. Also, if +// a RIFF header has been included then it should be updated as well or the +// WavPack file will not be directly unpackable to a valid wav file (although +// it will still be usable by itself). A return of FALSE indicates an error. + +static const uint32_t xtable [] = { 123, 3, 27, 59, 123, 187, 251 }; +static const uint32_t f_xtable [] = { 251, 3, 27, 59, 123, 187, 251 }; +static const uint32_t h_xtable [] = { 91, 3, 27, 91, 123, 187, 251 }; + +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples) +{ + uint32_t flags = (config->bytes_per_sample - 1), bps = 0, shift = 0; + uint32_t chan_mask = config->channel_mask; + int num_chans = config->num_channels; + int i; + + wpc->total_samples = total_samples; + wpc->config.sample_rate = config->sample_rate; + wpc->config.num_channels = config->num_channels; + wpc->config.channel_mask = config->channel_mask; + wpc->config.bits_per_sample = config->bits_per_sample; + wpc->config.bytes_per_sample = config->bytes_per_sample; + wpc->config.block_samples = config->block_samples; + wpc->config.flags = config->flags; + + if (config->float_norm_exp) { + wpc->config.float_norm_exp = config->float_norm_exp; + flags |= FLOAT_DATA; + } + else + shift = (config->bytes_per_sample * 8) - config->bits_per_sample; + + for (i = 0; i < 15; ++i) + if (wpc->config.sample_rate == sample_rates [i]) + break; + + flags |= i << SRATE_LSB; + flags |= shift << SHIFT_LSB; + + if (config->flags & CONFIG_HYBRID_FLAG) { + flags |= HYBRID_FLAG | HYBRID_BITRATE | HYBRID_BALANCE; + + if (!(wpc->config.flags & CONFIG_SHAPE_OVERRIDE)) { + wpc->config.flags |= CONFIG_HYBRID_SHAPE | CONFIG_AUTO_SHAPING; + flags |= HYBRID_SHAPE | NEW_SHAPING; + } + else if (wpc->config.flags & CONFIG_HYBRID_SHAPE) { + wpc->config.shaping_weight = config->shaping_weight; + flags |= HYBRID_SHAPE | NEW_SHAPING; + } + + if (wpc->config.flags & CONFIG_OPTIMIZE_WVC) + flags |= CROSS_DECORR; + + if (config->flags & CONFIG_BITRATE_KBPS) { + bps = floor (config->bitrate * 256000.0 / config->sample_rate / config->num_channels + 0.5); + + if (bps > (64 << 8)) + bps = 64 << 8; + } + else + bps = floor (config->bitrate * 256.0 + 0.5); + } + else + flags |= CROSS_DECORR; + + if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO)) + flags |= JOINT_STEREO; + + if (config->flags & CONFIG_CREATE_WVC) + wpc->wvc_flag = TRUE; + + for (wpc->current_stream = 0; num_chans; wpc->current_stream++) { + WavpackStream *wps = malloc (sizeof (WavpackStream)); + uint32_t stereo_mask, mono_mask; + int pos, chans; + + wpc->streams [wpc->current_stream] = wps; + CLEAR (*wps); + + for (pos = 1; pos <= 18; ++pos) { + stereo_mask = 3 << (pos - 1); + mono_mask = 1 << (pos - 1); + + if ((chan_mask & stereo_mask) == stereo_mask && (mono_mask & 0x251)) { + chan_mask &= ~stereo_mask; + chans = 2; + break; + } + else if (chan_mask & mono_mask) { + chan_mask &= ~mono_mask; + chans = 1; + break; + } + } + + if (pos == 19) + chans = num_chans > 1 ? 2 : 1; + + num_chans -= chans; + + if (num_chans && wpc->current_stream == MAX_STREAMS - 1) + break; + + memcpy (wps->wphdr.ckID, "wvpk", 4); + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + wps->wphdr.total_samples = wpc->total_samples; + wps->wphdr.version = 0x403; + wps->wphdr.flags = flags; + wps->bits = bps; + + if (!wpc->current_stream) + wps->wphdr.flags |= INITIAL_BLOCK; + + if (!num_chans) + wps->wphdr.flags |= FINAL_BLOCK; + + if (chans == 1) { + wps->wphdr.flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE); + wps->wphdr.flags |= MONO_FLAG; + } + } + + wpc->num_streams = wpc->current_stream; + wpc->current_stream = 0; + + if (num_chans) { + strcpy (wpc->error_message, "too many channels!"); + return FALSE; + } + + if (config->flags & CONFIG_EXTRA_MODE) { + + if (config->flags & CONFIG_HIGH_FLAG) + wpc->config.extra_flags = h_xtable [config->xmode]; + else if (config->flags & CONFIG_FAST_FLAG) + wpc->config.extra_flags = f_xtable [config->xmode]; + else + wpc->config.extra_flags = xtable [config->xmode]; + + if (config->flags & CONFIG_JOINT_OVERRIDE) + wpc->config.extra_flags &= ~EXTRA_STEREO_MODES; + } + + return TRUE; +} + +// Prepare to actually pack samples by determining the size of the WavPack +// blocks and allocating sample buffers and initializing each stream. Call +// after WavpackSetConfiguration() and before WavpackPackSamples(). A return +// of FALSE indicates an error. + +int WavpackPackInit (WavpackContext *wpc) +{ + if (wpc->metabytes > 4096) + write_metadata_block (wpc); + + if (wpc->config.block_samples) + wpc->block_samples = wpc->config.block_samples; + else { + if (wpc->config.flags & CONFIG_HIGH_FLAG) + wpc->block_samples = wpc->config.sample_rate; +// else if ((wpc->config.flags & CONFIG_FAST_FLAG) && !(wpc->config.sample_rate % 4)) +// wpc->block_samples = wpc->config.sample_rate / 4; + else if (!(wpc->config.sample_rate % 2)) + wpc->block_samples = wpc->config.sample_rate / 2; + else + wpc->block_samples = wpc->config.sample_rate; + + while (wpc->block_samples * wpc->config.num_channels > 100000) + wpc->block_samples /= 2; + + while (wpc->block_samples * wpc->config.num_channels < 40000) + wpc->block_samples *= 2; + } + + wpc->max_samples = wpc->block_samples + (wpc->block_samples >> 1); + + for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + wps->sample_buffer = malloc (wpc->max_samples * (wps->wphdr.flags & MONO_FLAG ? 4 : 8)); + pack_init (wpc); + } + + return TRUE; +} + +// Pack the specified samples. Samples must be stored in longs in the native +// endian format of the executing processor. The number of samples specified +// indicates composite samples (sometimes called "frames"). So, the actual +// number of data points would be this "sample_count" times the number of +// channels. Note that samples are accumulated here until enough exist to +// create a complete WavPack block (or several blocks for multichannel audio). +// If an application wants to break a block at a specific sample, then it must +// simply call WavpackFlushSamples() to force an early termination. Completed +// WavPack blocks are send to the function provided in the initial call to +// WavpackOpenFileOutput(). A return of FALSE indicates an error. + +static int pack_streams (WavpackContext *wpc, uint32_t block_samples); + +int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count) +{ + int nch = wpc->config.num_channels; + + while (sample_count) { + int32_t *source_pointer = sample_buffer; + uint samples_to_copy; + + if (wpc->acc_samples + sample_count > wpc->max_samples) + samples_to_copy = wpc->max_samples - wpc->acc_samples; + else + samples_to_copy = sample_count; + + for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int32_t *dptr, *sptr, cnt; + + dptr = wps->sample_buffer + wpc->acc_samples * (wps->wphdr.flags & MONO_FLAG ? 1 : 2); + sptr = source_pointer; + cnt = samples_to_copy; + + if (wps->wphdr.flags & MONO_FLAG) { + while (cnt--) { + *dptr++ = *sptr; + sptr += nch; + } + + source_pointer++; + } + else { + while (cnt--) { + *dptr++ = sptr [0]; + *dptr++ = sptr [1]; + sptr += nch; + } + + source_pointer += 2; + } + } + + sample_buffer += samples_to_copy * nch; + sample_count -= samples_to_copy; + + if ((wpc->acc_samples += samples_to_copy) == wpc->max_samples && + !pack_streams (wpc, wpc->block_samples)) + return FALSE; + } + + return TRUE; +} + +// Flush all accumulated samples into WavPack blocks. This is normally called +// after all samples have been sent to WavpackPackSamples(), but can also be +// called to terminate a WavPack block at a specific sample (in other words it +// is possible to continue after this operation). This is also called to +// dump non-audio blocks like those holding metadata for various purposes. +// A return of FALSE indicates an error. + +int WavpackFlushSamples (WavpackContext *wpc) +{ + while (wpc->acc_samples) { + uint32_t block_samples; + + if (wpc->acc_samples > wpc->block_samples) + block_samples = wpc->acc_samples / 2; + else + block_samples = wpc->acc_samples; + + if (!pack_streams (wpc, block_samples)) + return FALSE; + } + + if (wpc->metacount) + write_metadata_block (wpc); + + return TRUE; +} + +// Add wrapper (currently RIFF only) to WavPack blocks. This should be called +// before sending any audio samples for the RIFF header or after all samples +// have been sent for any RIFF trailer. WavpackFlushSamples() should be called +// between sending the last samples and calling this for trailer data to make +// sure that headers and trailers don't get mixed up in very short files. If +// the exact contents of the RIFF header are not known because, for example, +// the file duration is uncertain or trailing chunks are possible, simply write +// a "dummy" header of the correct length. When all data has been written it +// will be possible to read the first block written and update the header +// directly. An example of this can be found in the Audition filter. A +// return of FALSE indicates an error. + +int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount) +{ + uint32_t index = WavpackGetSampleIndex (wpc); + + return add_to_metadata (wpc, data, bcount, + (uchar)((!index || index == (uint32_t) -1) ? ID_RIFF_HEADER : ID_RIFF_TRAILER)); +} + +// Store computed MD5 sum in WavPack metadata. Note that the user must compute +// the 16 byte sum; it is not done here. A return of FALSE indicates an error. + +int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]) +{ + return add_to_metadata (wpc, data, 16, ID_MD5_CHECKSUM); +} + +static int pack_streams (WavpackContext *wpc, uint32_t block_samples) +{ + uint32_t max_blocksize = block_samples * 10 + 4096, bcount; + uchar *outbuff, *outend, *out2buff, *out2end; + int result; + + out2buff = (wpc->wvc_flag) ? malloc (max_blocksize) : NULL; + out2end = out2buff + max_blocksize; + outbuff = malloc (max_blocksize); + outend = outbuff + max_blocksize; + + for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags; + + flags &= ~MAG_MASK; + flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); + + wps->wphdr.block_index = wps->sample_index; + wps->wphdr.block_samples = block_samples; + wps->wphdr.flags = flags; + wps->block2buff = out2buff; + wps->block2end = out2end; + wps->blockbuff = outbuff; + wps->blockend = outend; + + result = pack_block (wpc, wps->sample_buffer); + wps->blockbuff = wps->block2buff = NULL; + + if (!result) { + strcpy (wpc->error_message, "output buffer overflowed!"); + break; + } + + bcount = ((WavpackHeader *) outbuff)->ckSize + 8; + native_to_little_endian ((WavpackHeader *) outbuff, WavpackHeaderFormat); + result = wpc->blockout (wpc->wv_out, outbuff, bcount); + + if (!result) { + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + break; + } + + wpc->filelen += bcount; + + if (out2buff) { + bcount = ((WavpackHeader *) out2buff)->ckSize + 8; + native_to_little_endian ((WavpackHeader *) out2buff, WavpackHeaderFormat); + result = wpc->blockout (wpc->wvc_out, out2buff, bcount); + + if (!result) { + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + break; + } + + wpc->file2len += bcount; + } + + if (wpc->acc_samples != block_samples) + memcpy (wps->sample_buffer, wps->sample_buffer + block_samples * (flags & MONO_FLAG ? 1 : 2), + (wpc->acc_samples - block_samples) * sizeof (int32_t) * (flags & MONO_FLAG ? 1 : 2)); + } + + wpc->current_stream = 0; + wpc->acc_samples -= block_samples; + free (outbuff); + + if (out2buff) + free (out2buff); + + return result; +} + +// Given the pointer to the first block written (to either a .wv or .wvc file), +// update the block with the actual number of samples written. This should +// be done if WavpackSetConfiguration() was called with an incorrect number +// of samples (or -1). It is the responsibility of the application to read and +// rewrite the block. An example of this can be found in the Audition filter. + +void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block) +{ + little_endian_to_native (wpc, WavpackHeaderFormat); + ((WavpackHeader *) first_block)->total_samples = WavpackGetSampleIndex (wpc); + native_to_little_endian (wpc, WavpackHeaderFormat); +} + +// Given the pointer to the first block written to a WavPack file, this +// function returns the location of the stored RIFF header that was originally +// written with WavpackAddWrapper(). This would normally be used to update +// the wav header to indicate that a different number of samples was actually +// written or if additional RIFF chunks are written at the end of the file. +// It is the responsibility of the application to read and rewrite the block. +// An example of this can be found in the Audition filter. + +void *WavpackGetWrapperLocation (void *first_block) +{ + if (((uchar *) first_block) [32] == ID_RIFF_HEADER) + return ((uchar *) first_block) + 34; + else + return NULL; +} + +#ifdef TAGS + +// Limited functionality to append APEv2 tags to WavPack files when they are +// created has been added for version 4.2. This function is used to append the +// specified field to the tag being created. If no tag has been started, then +// an empty one will be allocated first. When finished, use WavpackWriteTag() +// to write the completed tag to the file. Note that ID3 tags are not +// supported and that no editing of existing tags is allowed (there are several +// fine libraries available for this). + +int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value) +{ + M_Tag *m_tag = &wpc->m_tag; + int vsize = strlen (value); + int isize = strlen (item); + + if (!m_tag->ape_tag_hdr.ID [0]) { + strncpy (m_tag->ape_tag_hdr.ID, "APETAGEX", sizeof (m_tag->ape_tag_hdr.ID)); + m_tag->ape_tag_hdr.version = 2000; + m_tag->ape_tag_hdr.length = sizeof (m_tag->ape_tag_hdr); + m_tag->ape_tag_hdr.item_count = 0; + m_tag->ape_tag_hdr.flags = 0x80000000; + } + + if (m_tag->ape_tag_hdr.ID [0] == 'A') { + int new_item_len = vsize + isize + 9, flags = 0; + char *p; + + m_tag->ape_tag_hdr.item_count++; + m_tag->ape_tag_hdr.length += new_item_len; + p = m_tag->ape_tag_data = realloc (m_tag->ape_tag_data, m_tag->ape_tag_hdr.length); + p += m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr) - new_item_len; + native_to_little_endian (&vsize, "L"); + native_to_little_endian (&flags, "L"); + * (int32_t *) p = vsize; p += 4; + * (int32_t *) p = flags; p += 4; + little_endian_to_native (&vsize, "L"); + little_endian_to_native (&flags, "L"); + strcpy (p, item); + p += isize + 1; + memcpy (p, value, vsize); + + return TRUE; + } + else + return FALSE; +} + +// Once a APEv2 tag has been created with WavpackAppendTag(), this function is +// used to write the completed tag to the end of the WavPack file. Note that +// this function uses the same "blockout" function that is used to write +// regular WavPack blocks, although that's where the similarity ends. + +int WavpackWriteTag (WavpackContext *wpc) +{ + M_Tag *m_tag = &wpc->m_tag; + int result = TRUE; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') { + m_tag->ape_tag_hdr.flags |= 0x20000000; + native_to_little_endian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)); + little_endian_to_native (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + + if (m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr)) + result = wpc->blockout (wpc->wv_out, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (m_tag->ape_tag_hdr)); + + m_tag->ape_tag_hdr.flags &= ~0x20000000; + native_to_little_endian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)); + little_endian_to_native (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + } + else if (m_tag->id3_tag.tag_id [0] == 'T') + result = wpc->blockout (wpc->wv_out, &m_tag->id3_tag, sizeof (m_tag->id3_tag)); + + if (!result) + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + + return result; +} + +#endif + +#endif + +// Get total number of samples contained in the WavPack file, or -1 if unknown + +uint32_t WavpackGetNumSamples (WavpackContext *wpc) +{ + return wpc ? wpc->total_samples : (uint32_t) -1; +} + +// Get the current sample index position, or -1 if unknown + +uint32_t WavpackGetSampleIndex (WavpackContext *wpc) +{ + if (wpc) { +#ifdef VER3 + if (wpc->stream3) + return get_sample_index3 (wpc); + else if (wpc->streams [0]) + return wpc->streams [0]->sample_index; +#else + if (wpc->streams [0]) + return wpc->streams [0]->sample_index; +#endif + } + + return (uint32_t) -1; +} + +// Get the number of errors encountered so far + +int WavpackGetNumErrors (WavpackContext *wpc) +{ + return wpc ? wpc->crc_errors : 0; +} + +// return TRUE if any uncorrected lossy blocks were actually written or read + +int WavpackLossyBlocks (WavpackContext *wpc) +{ + return wpc ? wpc->lossy_blocks : 0; +} + +// Calculate the progress through the file as a double from 0.0 (for begin) +// to 1.0 (for done). A return value of -1.0 indicates that the progress is +// unknown. + +double WavpackGetProgress (WavpackContext *wpc) +{ + if (wpc && wpc->total_samples != (uint32_t) -1 && wpc->total_samples != 0) + return (double) WavpackGetSampleIndex (wpc) / wpc->total_samples; + else + return -1.0; +} + +// Return the total size of the WavPack file(s) in bytes. + +uint32_t WavpackGetFileSize (WavpackContext *wpc) +{ + return wpc ? wpc->filelen + wpc->file2len : 0; +} + +// Calculate the ratio of the specified WavPack file size to the size of the +// original audio data as a double greater than 0.0 and (usually) smaller than +// 1.0. A value greater than 1.0 represents "negative" compression and a +// return value of 0.0 indicates that the ratio cannot be determined. + +double WavpackGetRatio (WavpackContext *wpc) +{ + if (wpc && wpc->total_samples != (uint32_t) -1 && wpc->filelen) { + double output_size = (double) wpc->total_samples * wpc->config.num_channels * + wpc->config.bytes_per_sample; + double input_size = (double) wpc->filelen + wpc->file2len; + + if (output_size >= 1.0 && input_size >= 1.0) + return input_size / output_size; + } + + return 0.0; +} + +// Calculate the average bitrate of the WavPack file in bits per second. A +// return of 0.0 indicates that the bitrate cannot be determined. An option is +// provided to use (or not use) any attendant .wvc file. + +double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc) +{ + if (wpc && wpc->total_samples != (uint32_t) -1 && wpc->filelen) { + double output_time = (double) wpc->total_samples / wpc->config.sample_rate; + double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0); + + if (output_time >= 1.0 && input_size >= 1.0) + return input_size * 8.0 / output_time; + } + + return 0.0; +} + +#ifdef UNPACK + +// Calculate the bitrate of the current WavPack file block in bits per second. +// This can be used for an "instant" bit display and gets updated from about +// 1 to 4 times per second. A return of 0.0 indicates that the bitrate cannot +// be determined. + +double WavpackGetInstantBitrate (WavpackContext *wpc) +{ + if (wpc->stream3) + return WavpackGetAverageBitrate (wpc, TRUE); + + if (wpc && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples) { + double output_time = (double) wpc->streams [0]->wphdr.block_samples / wpc->config.sample_rate; + double input_size = 0; + int si; + + for (si = 0; si < wpc->num_streams; ++si) { + if (wpc->streams [si]->blockbuff) + input_size += ((WavpackHeader *) wpc->streams [si]->blockbuff)->ckSize; + + if (wpc->streams [si]->block2buff) + input_size += ((WavpackHeader *) wpc->streams [si]->block2buff)->ckSize; + } + + if (output_time > 0.0 && input_size >= 1.0) + return input_size * 8.0 / output_time; + } + + return 0.0; +} + +#endif + +// Close the specified WavPack file and release all resources used by it. +// Returns NULL. + +WavpackContext *WavpackCloseFile (WavpackContext *wpc) +{ + free_streams (wpc); + + if (wpc->streams [0]) + free (wpc->streams [0]); + +#ifdef VER3 + if (wpc->stream3) + free_stream3 (wpc); +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + if (wpc->close_files) { +#ifdef USE_FSTREAMS + if (wpc->wv_in != NULL) + fclose (wpc->wv_in); + + if (wpc->wvc_in != NULL) + fclose (wpc->wvc_in); +#endif + } + + WavpackFreeWrapper (wpc); +#endif + +#ifdef TAGS + free_tag (&wpc->m_tag); +#endif + + free (wpc); + + return NULL; +} + +// Returns the sample rate of the specified WavPack file + +uint32_t WavpackGetSampleRate (WavpackContext *wpc) +{ + return wpc ? wpc->config.sample_rate : 44100; +} + +// Returns the number of channels of the specified WavPack file. Note that +// this is the actual number of channels contained in the file even if the +// OPEN_2CH_MAX flag was specified when the file was opened. + +int WavpackGetNumChannels (WavpackContext *wpc) +{ + return wpc ? wpc->config.num_channels : 2; +} + +int WavpackGetFloatNormExp (WavpackContext *wpc) +{ + return wpc->config.float_norm_exp; +} + +// Returns the actual number of valid bits per sample contained in the +// original file, which may or may not be a multiple of 8. Floating data +// always has 32 bits, integers may be from 1 to 32 bits each. When this +// value is not a multiple of 8, then the "extra" bits are located in the +// LSBs of the results. That is, values are right justified when unpacked +// into ints, but are left justified in the number of bytes used by the +// original data. + +int WavpackGetBitsPerSample (WavpackContext *wpc) +{ + return wpc ? wpc->config.bits_per_sample : 16; +} + +// Returns the number of bytes used for each sample (1 to 4) in the original +// file. This is required information for the user of this module because the +// audio data is returned in the LOWER bytes of the long buffer and must be +// left-shifted 8, 16, or 24 bits if normalized longs are required. + +int WavpackGetBytesPerSample (WavpackContext *wpc) +{ + return wpc ? wpc->config.bytes_per_sample : 2; +} + +#if defined(UNPACK) || defined(INFO_ONLY) + +// If the OPEN_2CH_MAX flag is specified when opening the file, this function +// will return the actual number of channels decoded from the file (which may +// or may not be less than the actual number of channels, but will always be +// 1 or 2). Normally, this will be the front left and right channels of a +// multichannel file. + +int WavpackGetReducedChannels (WavpackContext *wpc) +{ + if (wpc) + return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels; + else + return 2; +} + +// These routines are used to access (and free) header and trailer data that +// was retrieved from the Wavpack file. The header will be available before +// the samples are decoded and the trailer will be available after all samples +// have been read. + +uint32_t WavpackGetWrapperBytes (WavpackContext *wpc) +{ + return wpc ? wpc->wrapper_bytes : 0; +} + +uchar *WavpackGetWrapperData (WavpackContext *wpc) +{ + return wpc ? wpc->wrapper_data : NULL; +} + +void WavpackFreeWrapper (WavpackContext *wpc) +{ + if (wpc && wpc->wrapper_data) { + free (wpc->wrapper_data); + wpc->wrapper_data = NULL; + wpc->wrapper_bytes = 0; + } +} + +// Get any MD5 checksum stored in the metadata (should be called after reading +// last sample or an extra seek will occur). A return value of FALSE indicates +// that no MD5 checksum was stored. + +static int seek_md5 (stream_reader *reader, void *id, uchar data [16]); + +int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]) +{ + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) { + if (wpc->config.md5_read) { + memcpy (data, wpc->config.md5_checksum, 16); + return TRUE; + } + else if (wpc->reader->can_seek (wpc->wv_in)) { + uint32_t pos_save = wpc->reader->get_pos (wpc->wv_in); + + wpc->config.md5_read = seek_md5 (wpc->reader, wpc->wv_in, wpc->config.md5_checksum); + wpc->reader->set_pos_abs (wpc->wv_in, pos_save); + + if (wpc->config.md5_read) { + memcpy (data, wpc->config.md5_checksum, 16); + return TRUE; + } + else + return FALSE; + } + } + + return FALSE; +} + +#endif + +// Free all memory allocated for raw WavPack blocks (for all allocated streams) +// and free all additonal streams. This does not free the default stream ([0]) +// which is always kept around. + +static void free_streams (WavpackContext *wpc) +{ + int si = wpc->num_streams; + + while (si--) { + if (wpc->streams [si]->blockbuff) { + free (wpc->streams [si]->blockbuff); + wpc->streams [si]->blockbuff = NULL; + } + + if (wpc->streams [si]->block2buff) { + free (wpc->streams [si]->block2buff); + wpc->streams [si]->block2buff = NULL; + } + + if (wpc->streams [si]->sample_buffer) { + free (wpc->streams [si]->sample_buffer); + wpc->streams [si]->sample_buffer = NULL; + } + + if (si) { + wpc->num_streams--; + free (wpc->streams [si]); + wpc->streams [si] = NULL; + } + } + + wpc->current_stream = 0; +} + +#ifdef TAGS + +// Return TRUE is a valid ID3v1 or APEv2 tag has been loaded. + +static int valid_tag (M_Tag *m_tag) +{ + if (m_tag->ape_tag_hdr.ID [0] == 'A') + return 'A'; + else if (m_tag->id3_tag.tag_id [0] == 'T') + return 'T'; + else + return 0; +} + +// Free the data for any APEv2 tag that was allocated. + +static void free_tag (M_Tag *m_tag) +{ + if (m_tag->ape_tag_data) { + free (m_tag->ape_tag_data); + m_tag->ape_tag_data = 0; + } +} + +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +// Read from current file position until a valid 32-byte WavPack 4.0 header is +// found and read into the specified pointer. The number of bytes skipped is +// returned. If no WavPack header is found within 1 meg, then a -1 is returned +// to indicate the error. No additional bytes are read past the header and it +// is returned in the processor's native endian mode. Seeking is not required. + +static uint32_t read_next_header (stream_reader *reader, void *id, WavpackHeader *wphdr) +{ + char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp; + uint32_t bytes_skipped = 0; + int bleft; + + while (1) { + if (sp < ep) { + bleft = ep - sp; + memcpy (buffer, sp, bleft); + } + else + bleft = 0; + + if (reader->read_bytes (id, buffer + bleft, sizeof (*wphdr) - bleft) != sizeof (*wphdr) - bleft) + return -1; + + sp = buffer; + + if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && + !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) { + memcpy (wphdr, buffer, sizeof (*wphdr)); + little_endian_to_native (wphdr, WavpackHeaderFormat); + return bytes_skipped; + } + + while (sp < ep && *sp != 'w') + sp++; + + if ((bytes_skipped += sp - buffer) > 1024 * 1024) + return -1; + } +} + +// This function is used to seek to end of a file to determine its actual +// length in samples by reading the last header block containing data. +// Currently, all WavPack files contain the sample length in the first block +// containing samples, however this might not always be the case. Obviously, +// this function requires a seekable file or stream and leaves the file +// pointer undefined. A return value of -1 indicates the length could not +// be determined. + +static uint32_t seek_final_index (stream_reader *reader, void *id) +{ + uint32_t result = (uint32_t) -1, bcount; + WavpackHeader wphdr; + + if (reader->get_length (id) > 1200000L) + reader->set_pos_rel (id, -1048576L, SEEK_END); + + while (1) { + bcount = read_next_header (reader, id, &wphdr); + + if (bcount == (uint32_t) -1) + return result; + + if (wphdr.block_samples && (wphdr.flags & FINAL_BLOCK)) + result = wphdr.block_index + wphdr.block_samples; + + if (wphdr.ckSize > sizeof (WavpackHeader) - 8) + reader->set_pos_rel (id, wphdr.ckSize - sizeof (WavpackHeader) + 8, SEEK_CUR); + } +} + +static int seek_md5 (stream_reader *reader, void *id, uchar data [16]) +{ + uchar meta_id, c1, c2; + uint32_t bcount, meta_bc; + WavpackHeader wphdr; + + if (reader->get_length (id) > 1200000L) + reader->set_pos_rel (id, -1048576L, SEEK_END); + + while (1) { + bcount = read_next_header (reader, id, &wphdr); + + if (bcount == (uint32_t) -1) + return FALSE; + + bcount = wphdr.ckSize - sizeof (WavpackHeader) + 8; + + while (bcount >= 2) { + if (reader->read_bytes (id, &meta_id, 1) != 1 || + reader->read_bytes (id, &c1, 1) != 1) + return FALSE; + + meta_bc = c1 << 1; + bcount -= 2; + + if (meta_id & ID_LARGE) { + if (bcount < 2 || reader->read_bytes (id, &c1, 1) != 1 || + reader->read_bytes (id, &c2, 1) != 1) + return FALSE; + + meta_bc += ((uint32_t) c1 << 9) + ((uint32_t) c2 << 17); + bcount -= 2; + } + + if (meta_id == ID_MD5_CHECKSUM) + return (meta_bc == 16 && bcount >= 16 && + reader->read_bytes (id, data, 16) == 16); + + reader->set_pos_rel (id, meta_bc, SEEK_CUR); + bcount -= meta_bc; + } + } +} + +#ifdef SEEKING + +// Find a valid WavPack header, searching either from the current file position +// (or from the specified position if not -1) and store it (endian corrected) +// at the specified pointer. The return value is the exact file position of the +// header, although we may have actually read past it. Because this function +// is used for seeking to a specific audio sample, it only considers blocks +// that contain audio samples for the initial stream to be valid. + +#define BUFSIZE 4096 + +static uint32_t find_header (stream_reader *reader, void *id, uint32_t filepos, WavpackHeader *wphdr) +{ + char *buffer = malloc (BUFSIZE), *sp = buffer, *ep = buffer; + + if (filepos != (uint32_t) -1 && reader->set_pos_abs (id, filepos)) { + free (buffer); + return -1; + } + + while (1) { + int bleft; + + if (sp < ep) { + bleft = ep - sp; + memcpy (buffer, sp, bleft); + ep -= (sp - buffer); + sp = buffer; + } + else { + if (sp > ep) + if (reader->set_pos_rel (id, sp - ep, SEEK_CUR)) { + free (buffer); + return -1; + } + + sp = ep = buffer; + bleft = 0; + } + + ep += reader->read_bytes (id, ep, BUFSIZE - bleft); + + if (ep - sp < 32) { + free (buffer); + return -1; + } + + while (sp + 32 <= ep) + if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && + !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) { + memcpy (wphdr, sp - 4, sizeof (*wphdr)); + little_endian_to_native (wphdr, WavpackHeaderFormat); + + if (wphdr->block_samples && (wphdr->flags & INITIAL_BLOCK)) { + free (buffer); + return reader->get_pos (id) - (ep - sp + 4); + } + + if (wphdr->ckSize > 1024) + sp += wphdr->ckSize - 1024; + } + } +} + +// Find the WavPack block that contains the specified sample. If "header_pos" +// is zero, then no information is assumed except the total number of samples +// in the file and its size in bytes. If "header_pos" is non-zero then we +// assume that it is the file position of the valid header image contained in +// the first stream and we can limit our search to either the portion above +// or below that point. If a .wvc file is being used, then this must be called +// for that file also. + +static uint32_t find_sample (WavpackContext *wpc, void *infile, uint32_t header_pos, uint32_t sample) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t file_pos1 = 0, file_pos2 = wpc->reader->get_length (infile); + uint32_t sample_pos1 = 0, sample_pos2 = wpc->total_samples; + double ratio = 0.96; + int file_skip = 0; + + if (sample >= wpc->total_samples) + return -1; + + if (header_pos) { + if (wps->wphdr.block_index > sample) { + sample_pos2 = wps->wphdr.block_index; + file_pos2 = header_pos; + } + else if (wps->wphdr.block_index + wps->wphdr.block_samples <= sample) { + sample_pos1 = wps->wphdr.block_index; + file_pos1 = header_pos; + } + else + return header_pos; + } + + while (1) { + double bytes_per_sample; + uint32_t seek_pos; + + bytes_per_sample = file_pos2 - file_pos1; + bytes_per_sample /= sample_pos2 - sample_pos1; + seek_pos = file_pos1 + (file_skip ? 32 : 0); + seek_pos += (uint32_t)(bytes_per_sample * (sample - sample_pos1) * ratio); + seek_pos = find_header (wpc->reader, infile, seek_pos, &wps->wphdr); + + if (seek_pos == (uint32_t) -1 || seek_pos >= file_pos2) { + if (ratio > 0.0) { + if ((ratio -= 0.24) < 0.0) + ratio = 0.0; + } + else + return -1; + } + else if (wps->wphdr.block_index > sample) { + sample_pos2 = wps->wphdr.block_index; + file_pos2 = seek_pos; + } + else if (wps->wphdr.block_index + wps->wphdr.block_samples <= sample) { + + if (seek_pos == file_pos1) + file_skip = 1; + else { + sample_pos1 = wps->wphdr.block_index; + file_pos1 = seek_pos; + } + } + else + return seek_pos; + } +} + +#endif + +#ifdef TAGS + +// This function attempts to load an ID3v1 or APEv2 tag from the specified +// file into the specified M_Tag structure. The ID3 tag fits in completely, +// but an APEv2 tag is variable length and so space must be allocated here +// to accomodate the data, and this will need to be freed later. A return +// value of TRUE indicates a valid tag was found and loaded. Note that the +// file pointer is undefined when this function exits. + +static int load_tag (WavpackContext *wpc) +{ + M_Tag *m_tag = &wpc->m_tag; + + CLEAR (*m_tag); + + // First, attempt to find an APEv2 tag... + + wpc->reader->set_pos_rel (wpc->wv_in, -sizeof (APE_Tag_Hdr), SEEK_END); + + if (wpc->reader->read_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (APE_Tag_Hdr)) == sizeof (APE_Tag_Hdr) && + !strncmp (m_tag->ape_tag_hdr.ID, "APETAGEX", 8)) { + + little_endian_to_native (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + + if (m_tag->ape_tag_hdr.version == 2000 && m_tag->ape_tag_hdr.item_count && + m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr) && + m_tag->ape_tag_hdr.length < (1024 * 1024) && + (m_tag->ape_tag_data = malloc (m_tag->ape_tag_hdr.length)) != NULL) { + + memset (m_tag->ape_tag_data, 0, m_tag->ape_tag_hdr.length); + wpc->reader->set_pos_rel (wpc->wv_in, -m_tag->ape_tag_hdr.length, SEEK_END); + + if (wpc->reader->read_bytes (wpc->wv_in, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr)) != + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr)) { + free (m_tag->ape_tag_data); + CLEAR (*m_tag); + return FALSE; + } + else + return TRUE; + } + } + + // ...if not, try a ID3v1 tag + + wpc->reader->set_pos_rel (wpc->wv_in, -sizeof (ID3_Tag), SEEK_END); + + if (wpc->reader->read_bytes (wpc->wv_in, &m_tag->id3_tag, sizeof (ID3_Tag)) == sizeof (ID3_Tag) && + !strncmp (m_tag->id3_tag.tag_id, "TAG", 3)) + return TRUE; + else { + CLEAR (*m_tag); + return FALSE; + } +} + +// Copy the specified ID3v1 tag value (with specified field size) from the +// source pointer to the destination, eliminating leading spaces and trailing +// spaces and nulls. + +static void tagcpy (char *dest, char *src, int tag_size) +{ + char *s1 = src, *s2 = src + tag_size - 1; + + while (s1 <= s2) + if (*s1 == ' ') + ++s1; + else if (!*s2 || *s2 == ' ') + --s2; + else + break; + + while (*s1 && s1 <= s2) + *dest++ = *s1++; + + *dest = 0; +} + +#endif + +#endif diff --git a/Libraries/WavPack/Files/wputils.h b/Libraries/WavPack/Files/wputils.h new file mode 100644 index 000000000..892a793ee --- /dev/null +++ b/Libraries/WavPack/Files/wputils.h @@ -0,0 +1,163 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wputils.h + +#ifndef WPUTILS_H +#define WPUTILS_H + +// This header file contains all the definitions required to use the +// functions in "wputils.c" to read and write WavPack files and streams. + +#include + +#if defined(_WIN32) && !defined(__MINGW32__) +#include +typedef unsigned __int64 uint64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int8 uint8_t; +typedef __int64 int64_t; +typedef __int32 int32_t; +typedef __int16 int16_t; +typedef __int8 int8_t; +typedef float float32_t; +#else +#include +#endif + +typedef unsigned char uchar; + +#if !defined(__GNUC__) || defined(WIN32) +typedef unsigned short ushort; +typedef unsigned int uint; +#endif + +///////////////////////// WavPack Configuration /////////////////////////////// + +// This external structure is used during encode to provide configuration to +// the encoding engine and during decoding to provide fle information back to +// the higher level functions. Not all fields are used in both modes. + +typedef struct { + float bitrate, shaping_weight; + int bits_per_sample, bytes_per_sample; + int qmode, flags, xmode, num_channels, float_norm_exp; + int32_t block_samples, extra_flags, sample_rate, channel_mask; + uchar md5_checksum [16], md5_read; + int num_tag_strings; + char **tag_strings; +} WavpackConfig; + +#define CONFIG_HYBRID_FLAG 8 // hybrid mode +#define CONFIG_JOINT_STEREO 0x10 // joint stereo +#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) +#define CONFIG_FAST_FLAG 0x200 // fast mode +#define CONFIG_HIGH_FLAG 0x800 // high quality mode +#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample +#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified +#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified +#define CONFIG_CREATE_WVC 0x80000 // create correction file +#define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression +#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode +#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode +#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints + +////////////// Callbacks used for reading & writing WavPack streams ////////// + +typedef struct { + int32_t (*read_bytes)(void *id, void *data, int32_t bcount); + uint32_t (*get_pos)(void *id); + int (*set_pos_abs)(void *id, uint32_t pos); + int (*set_pos_rel)(void *id, int32_t delta, int mode); + int (*push_back_byte)(void *id, int c); + uint32_t (*get_length)(void *id); + int (*can_seek)(void *id); +} stream_reader; + +typedef int (*blockout)(void *id, void *data, int32_t bcount); + +//////////////////////// function prototypes and macros ////////////////////// + +typedef void WavpackContext; + +#ifdef __cplusplus +extern "C" { +#endif + +WavpackContext *WavpackOpenFileInputEx (stream_reader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset); +WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset); + +#define OPEN_WVC 0x1 // open/read "correction" file +#define OPEN_TAGS 0x2 // read ID3v1 / APEv2 tags (seekable file) +#define OPEN_WRAPPER 0x4 // make audio wrapper available (i.e. RIFF) +#define OPEN_2CH_MAX 0x8 // open multichannel as stereo (no downmix) +#define OPEN_NORMALIZE 0x10 // normalize floating point data to +/- 1.0 +#define OPEN_STREAMING 0x20 // "streaming" mode blindly unpacks blocks + // w/o regard to header file position info + +int WavpackGetMode (WavpackContext *wpc); + +#define MODE_WVC 0x1 +#define MODE_LOSSLESS 0x2 +#define MODE_HYBRID 0x4 +#define MODE_FLOAT 0x8 +#define MODE_VALID_TAG 0x10 +#define MODE_HIGH 0x20 +#define MODE_FAST 0x40 +#define MODE_EXTRA 0x80 +#define MODE_APETAG 0x100 +#define MODE_SFX 0x200 + +int WavpackGetVersion (WavpackContext *wpc); +uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); +uint32_t WavpackGetNumSamples (WavpackContext *wpc); +uint32_t WavpackGetSampleIndex (WavpackContext *wpc); +int WavpackGetNumErrors (WavpackContext *wpc); +int WavpackLossyBlocks (WavpackContext *wpc); +int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); +WavpackContext *WavpackCloseFile (WavpackContext *wpc); +uint32_t WavpackGetSampleRate (WavpackContext *wpc); +int WavpackGetBitsPerSample (WavpackContext *wpc); +int WavpackGetBytesPerSample (WavpackContext *wpc); +int WavpackGetNumChannels (WavpackContext *wpc); +int WavpackGetReducedChannels (WavpackContext *wpc); +int WavpackGetFloatNormExp (WavpackContext *wpc); +int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); +uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); +uchar *WavpackGetWrapperData (WavpackContext *wpc); +void WavpackFreeWrapper (WavpackContext *wpc); +double WavpackGetProgress (WavpackContext *wpc); +uint32_t WavpackGetFileSize (WavpackContext *wpc); +double WavpackGetRatio (WavpackContext *wpc); +double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); +double WavpackGetInstantBitrate (WavpackContext *wpc); +int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size); +int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value); +int WavpackWriteTag (WavpackContext *wpc); + + +WavpackContext *WavpackOpenFileOutput (blockout blockout, void *wv_id, void *wvc_id); +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); +int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); +int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]); +int WavpackPackInit (WavpackContext *wpc); +int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); +int WavpackFlushSamples (WavpackContext *wpc); +void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); +void *WavpackGetWrapperLocation (void *first_block); + +// this function is not actually in wputils.c, but is generally useful + +void float_normalize (int32_t *values, int32_t num_values, int delta_exp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Libraries/WavPack/Files/wvunpack.c b/Libraries/WavPack/Files/wvunpack.c new file mode 100644 index 000000000..d4e776de5 --- /dev/null +++ b/Libraries/WavPack/Files/wvunpack.c @@ -0,0 +1,926 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wvunpack.c + +// This is the main module for the WavPack command-line decompressor. + +#if defined(WIN32) +#include +#include +#else +#include +#include +#if defined (__GNUC__) +#include +#include +#endif +#endif + +#ifdef __BORLANDC__ +#include +#elif defined(__GNUC__) && !defined(WIN32) +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include "wavpack.h" +#include "md5.h" + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +static char *strdup (const char *s) + { char *d = malloc (strlen (s) + 1); return strcpy (d, s); } +#endif + +///////////////////////////// local variable storage ////////////////////////// + +static const char *sign_on = "\n" +" WVUNPACK Hybrid Lossless Wavefile Decompressor %s Version %s %s\n" +" Copyright (c) 1998 - 2005 Conifer Software. All Rights Reserved.\n\n"; + +static const char *usage = +" Usage: WVUNPACK [-options] [@]infile[.wv]|- [[@]outfile[.wav]|outpath|-]\n" +" (infile may contain wildcards: ?,*)\n\n" +" Options: -d = delete source file if successful (use with caution!)\n" +" -i = ignore .wvc file (forces hybrid lossy decompression)\n" +" -m = calculate and display MD5 signature; verify if lossless\n" +" -q = quiet (keep console output to a minimum)\n" +" -r = force raw audio decode (skip RIFF headers & trailers)\n" +" -s = display summary information only to stdout (no decode)\n" +#if defined (WIN32) +" -t = copy input file's time stamp to output file(s)\n" +#endif +" -v = verify source data only (no output file created)\n" +" -y = yes to overwrite warning (use with caution!)\n\n" +" Web: Visit www.wavpack.com for latest version and info\n"; + +static char overwrite_all = 0, delete_source = 0, raw_decode = 0, summary = 0, + ignore_wvc = 0, quiet_mode = 0, calc_md5 = 0, copy_time = 0; + +static int num_files, file_index, outbuf_k; + +/////////////////////////// local function declarations /////////////////////// + +static int unpack_file (char *infilename, char *outfilename); +static void display_progress (double file_progress); + +#define NO_ERROR 0L +#define SOFT_ERROR 1 +#define HARD_ERROR 2 + +////////////////////////////////////////////////////////////////////////////// +// The "main" function for the command-line WavPack decompressor. // +////////////////////////////////////////////////////////////////////////////// + +int main (argc, argv) int argc; char **argv; +{ + int verify_only = 0, usage_error = 0, filelist = 0, add_extension = 0; + char *infilename = NULL, *outfilename = NULL; + char outpath, **matches = NULL; + int result, i; + +#ifdef __BORLANDC__ + struct ffblk ffblk; +#elif defined(WIN32) + struct _finddata_t _finddata_t; +#else + glob_t globs; + struct stat fstats; +#endif + + // loop through command-line arguments + + while (--argc) { +#if defined (WIN32) + if ((**++argv == '-' || **argv == '/') && (*argv)[1]) +#else + if ((**++argv == '-') && (*argv)[1]) +#endif + while (*++*argv) + switch (**argv) { + case 'Y': case 'y': + overwrite_all = 1; + break; + + case 'D': case 'd': + delete_source = 1; + break; +#if defined (WIN32) + case 'T': case 't': + copy_time = 1; + break; +#endif + case 'V': case 'v': + verify_only = 1; + break; + + case 'S': case 's': + summary = 1; + break; + + case 'K': case 'k': + outbuf_k = strtol (++*argv, argv, 10); + --*argv; + break; + + case 'M': case 'm': + calc_md5 = 1; + break; + + case 'R': case 'r': + raw_decode = 1; + break; + + case 'Q': case 'q': + quiet_mode = 1; + break; + + case 'I': case 'i': + ignore_wvc = 1; + break; + + default: + error_line ("illegal option: %c !", **argv); + usage_error = 1; + } + else { + if (!infilename) { + infilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (infilename, *argv); + } + else if (!outfilename) { + outfilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (outfilename, *argv); + } + else { + error_line ("extra unknown argument: %s !", *argv); + usage_error = 1; + } + } + } + + // check for various command-line argument problems + + if (verify_only && delete_source) { + error_line ("can't delete in verify mode!"); + delete_source = 0; + } + + if (verify_only && outfilename) { + error_line ("outfile specification and verify mode are incompatible!"); + usage_error = 1; + } + + if (!quiet_mode && !usage_error) + fprintf (stderr, sign_on, VERSION_OS, VERSION_STR, DATE_STR); + + if (!infilename) { + printf ("%s", usage); + return 0; + } + + if (usage_error) { + free (infilename); + return 0; + } + + setup_break (); + + // If the infile specification begins with a '@', then it actually points + // to a file that contains the names of the files to be converted. This + // was included for use by Wim Speekenbrink's frontends, but could be used + // for other purposes. + + if (infilename [0] == '@') { + FILE *list = fopen (infilename+1, "rt"); + int c; + + if (list == NULL) { + error_line ("file %s not found!", infilename+1); + free(infilename); + return 1; + } + + while ((c = getc (list)) != EOF) { + + while (c == '\n') + c = getc (list); + + if (c != EOF) { + char *fname = malloc (PATH_MAX); + int ci = 0; + + do + fname [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + fname [ci++] = '\0'; + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = realloc (fname, ci); + } + } + + fclose (list); + free (infilename); + infilename = NULL; + filelist = 1; + } + else if (*infilename != '-') { // skip this if infile is stdin (-) + if (!filespec_ext (infilename)) + strcat (infilename, ".wv"); + +#ifdef NO_WILDCARDS + matches = malloc (sizeof (*matches)); + matches [num_files++] = infilename; + filelist = 1; +#else + // search for and store any filenames that match the user supplied spec + +#ifdef __BORLANDC__ + if (findfirst (infilename, &ffblk, 0) == 0) { + do { + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = strdup (ffblk.ff_name); + } while (findnext (&ffblk) == 0); + } +#elif defined (WIN32) + if ((i = _findfirst (infilename, &_finddata_t)) != -1L) { + do { + if (!(_finddata_t.attrib & _A_SUBDIR)) { + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = strdup (_finddata_t.name); + } + } while (_findnext (i, &_finddata_t) == 0); + + _findclose (i); + } +#else + i = 0; + if (glob(infilename, 0, NULL, &globs) == 0 && globs.gl_pathc > 0) { + do { + if (stat(globs.gl_pathv[i], &fstats) == 0 && !(fstats.st_mode & S_IFDIR)) { + matches = realloc (matches, ++num_files * sizeof (*matches)); + matches [num_files - 1] = strdup (globs.gl_pathv[i]); + } + } while (i++ < globs.gl_pathc); + } + globfree(&globs); +#endif +#endif + } + else { // handle case of stdin (-) + matches = malloc (sizeof (*matches)); + matches [num_files++] = infilename; + } + + // If the outfile specification begins with a '@', then it actually points + // to a file that contains the output specification. This was included for + // use by Wim Speekenbrink's frontends because certain filenames could not + // be passed on the command-line, but could be used for other purposes. + + if (outfilename && outfilename [0] == '@') { + FILE *list = fopen (outfilename+1, "rt"); + int c; + + if (list == NULL) { + error_line ("file %s not found!", outfilename+1); + free(outfilename); + return 1; + } + + while ((c = getc (list)) == '\n'); + + if (c != EOF) { + int ci = 0; + + do + outfilename [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + outfilename [ci] = '\0'; + } + else { + error_line ("output spec file is empty!"); + free(outfilename); + fclose (list); + return 1; + } + + fclose (list); + } + + // if we found any files to process, this is where we start + + if (num_files) { + int soft_errors = 0; + + if (outfilename && *outfilename != '-') { + outpath = (filespec_path (outfilename) != NULL); + + if (num_files > 1 && !outpath) { + error_line ("%s is not a valid output path", outfilename); + free(outfilename); + return 1; + } + } + else + outpath = 0; + + add_extension = !outfilename || outpath || !filespec_ext (outfilename); + + // loop through and process files in list + + for (file_index = 0; file_index < num_files; ++file_index) { + if (check_break ()) + break; + + // get input filename from list + + if (filelist) + infilename = matches [file_index]; + else if (*infilename != '-') { + *filespec_name (infilename) = '\0'; + strcat (infilename, matches [file_index]); + } + + // generate output filename + + if (outpath) { + strcat (outfilename, filespec_name (matches [file_index])); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + else if (!outfilename) { + outfilename = malloc (strlen (infilename) + 10); + strcpy (outfilename, infilename); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + + if (outfilename && *outfilename != '-' && add_extension) + strcat (outfilename, raw_decode ? ".raw" : ".wav"); + + if (num_files > 1) + fprintf (stderr, "\n%s:\n", infilename); + + result = unpack_file (infilename, verify_only ? NULL : outfilename); + + if (result == HARD_ERROR) + break; + else if (result == SOFT_ERROR) + ++soft_errors; + + // clean up in preparation for potentially another file + + if (outpath) + *filespec_name (outfilename) = '\0'; + else if (*outfilename != '-') { + free (outfilename); + outfilename = NULL; + } + + free (matches [file_index]); + } + + if (num_files > 1) { + if (soft_errors) + fprintf (stderr, "\n **** warning: errors occurred in %d of %d files! ****\n", soft_errors, num_files); + else if (!quiet_mode) + fprintf (stderr, "\n **** %d files successfully processed ****\n", num_files); + } + + free (matches); + } + else + error_line (filespec_wild (infilename) ? "nothing to do!" : + "file %s not found!", infilename); + + if (outfilename) + free(outfilename); + +#ifdef DEBUG_ALLOC + error_line ("malloc_count = %d", dump_alloc ()); +#endif + + return 0; +} + +// Unpack the specified WavPack input file into the specified output file name. +// This function uses the library routines provided in wputils.c to do all +// unpacking. This function takes care of reformatting the data (which is +// returned in native-endian longs) to the standard little-endian format. This +// function also handles optionally calculating and displaying the MD5 sum of +// the resulting audio data and verifying the sum if a sum was stored in the +// source and lossless compression is used. + +static uchar *format_samples (int bps, uchar *dst, int32_t *src, uint32_t samcnt); +static void dump_summary (WavpackContext *wpc, char *name, FILE *dst); + +extern int delta_blocks [8]; + +static int unpack_file (char *infilename, char *outfilename) +{ + int result = NO_ERROR, md5_diff = FALSE, open_flags = 0, bytes_per_sample, num_channels, wvc_mode, bps; + uint32_t outfile_length, output_buffer_size, bcount, total_unpacked_samples = 0; + uchar *output_buffer = NULL, *output_pointer = NULL; + double dtime, progress = -1.0; + MD5_CTX md5_context; + WavpackContext *wpc; + int32_t *temp_buffer; + char error [80]; + FILE *outfile; + +#ifdef __BORLANDC__ + struct time time1, time2; +#elif defined(WIN32) + struct _timeb time1, time2; +#else + struct timeval time1, time2; + struct timezone timez; +#endif + + // use library to open WavPack file + + if (outfilename && !raw_decode) + open_flags |= OPEN_WRAPPER; + + if (raw_decode) + open_flags |= OPEN_STREAMING; + + if (!ignore_wvc) + open_flags |= OPEN_WVC; + + wpc = WavpackOpenFileInput (infilename, error, open_flags, 0); + + if (!wpc) { + error_line (error); + return SOFT_ERROR; + } + + if (calc_md5) + MD5Init (&md5_context); + + wvc_mode = WavpackGetMode (wpc) & MODE_WVC; + num_channels = WavpackGetNumChannels (wpc); + bps = WavpackGetBytesPerSample (wpc); + bytes_per_sample = num_channels * bps; + + if (summary) { + dump_summary (wpc, infilename, stdout); + WavpackCloseFile (wpc); + return NO_ERROR; + } + + if (outfilename) { + if (*outfilename != '-') { + + // check the output file for overwrite warning required + + if (!overwrite_all && (outfile = fopen (outfilename, "rb")) != NULL) { + DoCloseHandle (outfile); + fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); + SetConsoleTitle ("overwrite?"); + + switch (yna ()) { + + case 'n': + result = SOFT_ERROR; + break; + + case 'a': + overwrite_all = 1; + } + + if (result != NO_ERROR) { + WavpackCloseFile (wpc); + return result; + } + } + + // open output file for writing + + if ((outfile = fopen (outfilename, "wb")) == NULL) { + error_line ("can't create file %s!", outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!quiet_mode) + fprintf (stderr, "restoring %s,", FN_FIT (outfilename)); + } + else { // come here to open stdout as destination + + outfile = stdout; +#if defined(WIN32) + setmode (fileno (stdout), O_BINARY); +#endif + + if (!quiet_mode) + fprintf (stderr, "unpacking %s%s to stdout,", *infilename == '-' ? + "stdin" : FN_FIT (infilename), wvc_mode ? " (+.wvc)" : ""); + } + + if (outbuf_k) + output_buffer_size = outbuf_k * 1024; + else + output_buffer_size = 1024 * 256; + + output_pointer = output_buffer = malloc (output_buffer_size); + } + else { // in verify only mode we don't worry about headers + outfile = NULL; + + if (!quiet_mode) + fprintf (stderr, "verifying %s%s,", *infilename == '-' ? "stdin" : + FN_FIT (infilename), wvc_mode ? " (+.wvc)" : ""); + } + +#ifdef __BORLANDC__ + gettime (&time1); +#elif defined(WIN32) + _ftime (&time1); +#else + gettimeofday(&time1,&timez); +#endif + + if (WavpackGetWrapperBytes (wpc)) { + if (outfile && (!DoWriteFile (outfile, WavpackGetWrapperData (wpc), WavpackGetWrapperBytes (wpc), &bcount) || + bcount != WavpackGetWrapperBytes (wpc))) { + error_line ("can't write .WAV data, disk probably full!"); + DoTruncateFile (outfile); + result = HARD_ERROR; + } + + WavpackFreeWrapper (wpc); + } + + temp_buffer = malloc (4096L * num_channels * 4); + + while (result == NO_ERROR) { + uint32_t samples_to_unpack, samples_unpacked; + + if (output_buffer) { + samples_to_unpack = (output_buffer_size - (output_pointer - output_buffer)) / bytes_per_sample; + + if (samples_to_unpack > 4096) + samples_to_unpack = 4096; + } + else + samples_to_unpack = 4096; + + samples_unpacked = WavpackUnpackSamples (wpc, temp_buffer, samples_to_unpack); + total_unpacked_samples += samples_unpacked; + + if (output_buffer) { + if (samples_unpacked) + output_pointer = format_samples (bps, output_pointer, temp_buffer, samples_unpacked * num_channels); + + if (!samples_unpacked || (output_buffer_size - (output_pointer - output_buffer)) < bytes_per_sample) { + if (!DoWriteFile (outfile, output_buffer, output_pointer - output_buffer, &bcount) || + bcount != output_pointer - output_buffer) { + error_line ("can't write .WAV data, disk probably full!"); + DoTruncateFile (outfile); + result = HARD_ERROR; + break; + } + + output_pointer = output_buffer; + } + } + + if (calc_md5 && samples_unpacked) { + format_samples (bps, (uchar *) temp_buffer, temp_buffer, samples_unpacked * num_channels); + MD5Update (&md5_context, temp_buffer, bps * samples_unpacked * num_channels); + } + + if (!samples_unpacked) + break; + + if (check_break ()) { + fprintf (stderr, "^C\n"); + DoTruncateFile (outfile); + result = SOFT_ERROR; + break; + } + + if (WavpackGetProgress (wpc) != -1.0 && + progress != floor (WavpackGetProgress (wpc) * 100.0 + 0.5)) { + int nobs = progress == -1.0; + + progress = WavpackGetProgress (wpc); + display_progress (progress); + progress = floor (progress * 100.0 + 0.5); + + if (!quiet_mode) + fprintf (stderr, "%s%3d%% done...", + nobs ? " " : "\b\b\b\b\b\b\b\b\b\b\b\b", (int) progress); + } + } + + free (temp_buffer); + + if (output_buffer) + free (output_buffer); + +if (0) { +int i; +for (i = 0; i < 8; ++i) + error_line ("delta = %d, count = %d", i, delta_blocks [i]); +} + + if (!check_break () && calc_md5) { + char md5_string1 [] = "00000000000000000000000000000000"; + char md5_string2 [] = "00000000000000000000000000000000"; + uchar md5_original [16], md5_unpacked [16]; + int i; + + MD5Final (md5_unpacked, &md5_context); + + if (WavpackGetMD5Sum (wpc, md5_original)) { + + for (i = 0; i < 16; ++i) + sprintf (md5_string1 + (i * 2), "%02x", md5_original [i]); + + error_line ("original md5: %s", md5_string1); + + if (memcmp (md5_unpacked, md5_original, 16)) + md5_diff = TRUE; + } + + for (i = 0; i < 16; ++i) + sprintf (md5_string2 + (i * 2), "%02x", md5_unpacked [i]); + + error_line ("unpacked md5: %s", md5_string2); + } + + if (WavpackGetWrapperBytes (wpc)) { + if (outfile && result == NO_ERROR && + (!DoWriteFile (outfile, WavpackGetWrapperData (wpc), WavpackGetWrapperBytes (wpc), &bcount) || + bcount != WavpackGetWrapperBytes (wpc))) { + error_line ("can't write .WAV data, disk probably full!"); + DoTruncateFile (outfile); + result = HARD_ERROR; + } + + WavpackFreeWrapper (wpc); + } + + // if we are not just in verify only mode, grab the size of the output + // file and close the file + + if (outfile != NULL) { + fflush (outfile); + outfile_length = DoGetFileSize (outfile); + + if (!DoCloseHandle (outfile)) { + error_line ("can't close file!"); + result = SOFT_ERROR; + } + + if (outfilename && *outfilename != '-' && !outfile_length) + DoDeleteFile (outfilename); + } + +#if defined (WIN32) + if (result == NO_ERROR && copy_time && outfilename && + !copy_timestamp (infilename, outfilename)) + error_line ("failure copying time stamp!"); +#endif + + if (result == NO_ERROR && WavpackGetNumSamples (wpc) != (uint32_t) -1 && + total_unpacked_samples != WavpackGetNumSamples (wpc)) { + error_line ("incorrect number of samples!"); + result = SOFT_ERROR; + } + + if (result == NO_ERROR && WavpackGetNumErrors (wpc)) { + error_line ("crc errors detected in %d block(s)!", WavpackGetNumErrors (wpc)); + result = SOFT_ERROR; + } + else if (result == NO_ERROR && md5_diff && (WavpackGetMode (wpc) & MODE_LOSSLESS)) { + error_line ("MD5 signatures should match, but do not!"); + result = SOFT_ERROR; + } + + // Compute and display the time consumed along with some other details of + // the unpacking operation (assuming there was no error). + +#ifdef __BORLANDC__ + gettime (&time2); + dtime = time2.ti_sec * 100.0 + time2.ti_hund + time2.ti_min * 6000.0 + time2.ti_hour * 360000.00; + dtime -= time1.ti_sec * 100.0 + time1.ti_hund + time1.ti_min * 6000.0 + time1.ti_hour * 360000.00; + + if ((dtime /= 100.0) < 0.0) + dtime += 86400.0; +#elif defined(WIN32) + _ftime (&time2); + dtime = time2.time + time2.millitm / 1000.0; + dtime -= time1.time + time1.millitm / 1000.0; +#else + gettimeofday(&time2,&timez); + dtime = time2.tv_sec + time2.tv_usec / 1000000.0; + dtime -= time1.tv_sec + time1.tv_usec / 1000000.0; +#endif + + if (result == NO_ERROR && !quiet_mode) { + char *file, *fext, *oper, *cmode, cratio [16] = ""; + + if (outfilename && *outfilename != '-') { + file = FN_FIT (outfilename); + fext = ""; + oper = "restored"; + } + else { + file = (*infilename == '-') ? "stdin" : FN_FIT (infilename); + fext = wvc_mode ? " (+.wvc)" : ""; + oper = outfilename ? "unpacked" : "verified"; + } + + if (WavpackGetMode (wpc) & MODE_LOSSLESS) { + cmode = "lossless"; + + if (WavpackGetRatio (wpc) != 0.0) + sprintf (cratio, ", %.2f%%", 100.0 - WavpackGetRatio (wpc) * 100.0); + } + else { + cmode = "lossy"; + + if (WavpackGetAverageBitrate (wpc, TRUE) != 0.0) + sprintf (cratio, ", %d kbps", (int) (WavpackGetAverageBitrate (wpc, TRUE) / 1000.0)); + } + + error_line ("%s %s%s in %.2f secs (%s%s)", oper, file, fext, dtime, cmode, cratio); + } + + WavpackCloseFile (wpc); + + if (result == NO_ERROR && delete_source) { + error_line ("%s source file %s", DoDeleteFile (infilename) ? + "deleted" : "can't delete", infilename); + + if (wvc_mode) { + char in2filename [PATH_MAX]; + + strcpy (in2filename, infilename); + strcat (in2filename, "c"); + + error_line ("%s source file %s", DoDeleteFile (in2filename) ? + "deleted" : "can't delete", in2filename); + } + } + + return result; +} + +// Reformat samples from longs in processor's native endian mode to +// little-endian data with (possibly) less than 4 bytes / sample. + +static uchar *format_samples (int bps, uchar *dst, int32_t *src, uint32_t samcnt) +{ + int32_t temp; + + switch (bps) { + + case 1: + while (samcnt--) + *dst++ = *src++ + 128; + + break; + + case 2: + while (samcnt--) { + *dst++ = (uchar) (temp = *src++); + *dst++ = (uchar) (temp >> 8); + } + + break; + + case 3: + while (samcnt--) { + *dst++ = (uchar) (temp = *src++); + *dst++ = (uchar) (temp >> 8); + *dst++ = (uchar) (temp >> 16); + } + + break; + + case 4: + while (samcnt--) { + *dst++ = (uchar) (temp = *src++); + *dst++ = (uchar) (temp >> 8); + *dst++ = (uchar) (temp >> 16); + *dst++ = (uchar) (temp >> 24); + } + + break; + } + + return dst; +} + +static void dump_summary (WavpackContext *wpc, char *name, FILE *dst) +{ + int num_channels = WavpackGetNumChannels (wpc); + uchar md5_sum [16], modes [80]; + + fprintf (dst, "\n"); + + if (name && *name != '-') { + fprintf (dst, "file name: %s%s\n", name, (WavpackGetMode (wpc) & MODE_WVC) ? " (+wvc)" : ""); + fprintf (dst, "file size: %lu bytes\n", WavpackGetFileSize (wpc)); + } + + fprintf (dst, "source: %d-bit %s at %ld Hz\n", WavpackGetBitsPerSample (wpc), + (WavpackGetMode (wpc) & MODE_FLOAT) ? "floats" : "ints", + WavpackGetSampleRate (wpc)); + + fprintf (dst, "channels: %d (%s)\n", num_channels, + num_channels > 2 ? "multichannel" : (num_channels == 1 ? "mono" : "stereo")); + + if (WavpackGetNumSamples (wpc) != (uint32_t) -1) { + double seconds = (double) WavpackGetNumSamples (wpc) / WavpackGetSampleRate (wpc); + int minutes = (int) floor (seconds / 60.0); + int hours = (int) floor (seconds / 3600.0); + + seconds -= minutes * 60.0; + minutes -= hours * 60.0; + + fprintf (dst, "duration: %d:%02d:%0.2f\n", hours, minutes, seconds); + } + + modes [0] = 0; + + if (WavpackGetMode (wpc) & MODE_HYBRID) + strcat (modes, "hybrid "); + + strcat (modes, (WavpackGetMode (wpc) & MODE_LOSSLESS) ? "lossless" : "lossy"); + + if (WavpackGetMode (wpc) & MODE_FAST) + strcat (modes, ", fast"); + else if (WavpackGetMode (wpc) & MODE_HIGH) + strcat (modes, ", high"); + + if (WavpackGetMode (wpc) & MODE_EXTRA) + strcat (modes, ", extra"); + + if (WavpackGetMode (wpc) & MODE_SFX) + strcat (modes, ", sfx"); + + fprintf (dst, "modalities: %s\n", modes); + + if (WavpackGetRatio (wpc) != 0.0) { + fprintf (dst, "compression: %.2f%%\n", 100.0 - (100 * WavpackGetRatio (wpc))); + fprintf (dst, "ave bitrate: %d kbps\n", (int) ((WavpackGetAverageBitrate (wpc, TRUE) + 500.0) / 1000.0)); + + if (WavpackGetMode (wpc) & MODE_WVC) + fprintf (dst, "ave lossy bitrate: %d kbps\n", (int) ((WavpackGetAverageBitrate (wpc, FALSE) + 500.0) / 1000.0)); + } + + if (WavpackGetVersion (wpc)) + fprintf (dst, "encoder version: %d\n", WavpackGetVersion (wpc)); + + if (WavpackGetMD5Sum (wpc, md5_sum)) { + char md5_string [] = "00000000000000000000000000000000"; + int i; + + for (i = 0; i < 16; ++i) + sprintf (md5_string + (i * 2), "%02x", md5_sum [i]); + + fprintf (dst, "original md5: %s\n", md5_string); + } +} + +////////////////////////////////////////////////////////////////////////////// +// This function displays the progress status on the title bar of the DOS // +// window that WavPack is running in. The "file_progress" argument is for // +// the current file only and ranges from 0 - 1; this function takes into // +// account the total number of files to generate a batch progress number. // +////////////////////////////////////////////////////////////////////////////// + +void display_progress (double file_progress) +{ + char title [40]; + + file_progress = (file_index + file_progress) / num_files; + sprintf (title, "%d%% (WvUnpack)", (int) ((file_progress * 100.0) + 0.5)); + SetConsoleTitle (title); +} diff --git a/Libraries/WavPack/Info.plist b/Libraries/WavPack/Info.plist new file mode 100644 index 000000000..8ebb0ad93 --- /dev/null +++ b/Libraries/WavPack/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleName + ${PRODUCT_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.yourcocoaframework + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + + + diff --git a/Libraries/WavPack/WavPack.xcodeproj/project.pbxproj b/Libraries/WavPack/WavPack.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a87ee035d --- /dev/null +++ b/Libraries/WavPack/WavPack.xcodeproj/project.pbxproj @@ -0,0 +1,386 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; + 8E7574B309F31BB90080F1EE /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574AF09F31BB90080F1EE /* md5.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E7574B409F31BB90080F1EE /* unpack3.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574B009F31BB90080F1EE /* unpack3.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E7574B509F31BB90080F1EE /* wavpack.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574B109F31BB90080F1EE /* wavpack.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E7574B609F31BB90080F1EE /* wputils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574B209F31BB90080F1EE /* wputils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E7574C509F31BD50080F1EE /* bits.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B709F31BD50080F1EE /* bits.c */; }; + 8E7574C609F31BD50080F1EE /* extra1.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B809F31BD50080F1EE /* extra1.c */; }; + 8E7574C709F31BD50080F1EE /* extra2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B909F31BD50080F1EE /* extra2.c */; }; + 8E7574C809F31BD50080F1EE /* float.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BA09F31BD50080F1EE /* float.c */; }; + 8E7574C909F31BD50080F1EE /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BB09F31BD50080F1EE /* md5.c */; }; + 8E7574CA09F31BD50080F1EE /* metadata.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BC09F31BD50080F1EE /* metadata.c */; }; + 8E7574CB09F31BD50080F1EE /* pack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BD09F31BD50080F1EE /* pack.c */; }; + 8E7574CC09F31BD50080F1EE /* unpack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BE09F31BD50080F1EE /* unpack.c */; }; + 8E7574CD09F31BD50080F1EE /* unpack3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BF09F31BD50080F1EE /* unpack3.c */; }; + 8E7574CE09F31BD50080F1EE /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C009F31BD50080F1EE /* utils.c */; }; + 8E7574D009F31BD50080F1EE /* words.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C209F31BD50080F1EE /* words.c */; }; + 8E7574D109F31BD50080F1EE /* wputils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C309F31BD50080F1EE /* wputils.c */; }; + 8E7574F509F31C7D0080F1EE /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E7574F409F31C7D0080F1EE /* libiconv.dylib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildStyle section */ + 014CEA440018CDF011CA2923 /* Debug */ = { + isa = PBXBuildStyle; + buildSettings = { + }; + name = Debug; + }; + 014CEA450018CDF011CA2923 /* Release */ = { + isa = PBXBuildStyle; + buildSettings = { + }; + name = Release; + }; +/* End PBXBuildStyle section */ + +/* Begin PBXFileReference section */ + 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8DC2EF5B0486A6940098B216 /* WavPack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WavPack.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8E7574AF09F31BB90080F1EE /* md5.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = md5.h; path = Files/md5.h; sourceTree = ""; }; + 8E7574B009F31BB90080F1EE /* unpack3.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = unpack3.h; path = Files/unpack3.h; sourceTree = ""; }; + 8E7574B109F31BB90080F1EE /* wavpack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wavpack.h; path = Files/wavpack.h; sourceTree = ""; }; + 8E7574B209F31BB90080F1EE /* wputils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wputils.h; path = Files/wputils.h; sourceTree = ""; }; + 8E7574B709F31BD50080F1EE /* bits.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bits.c; path = Files/bits.c; sourceTree = ""; }; + 8E7574B809F31BD50080F1EE /* extra1.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra1.c; path = Files/extra1.c; sourceTree = ""; }; + 8E7574B909F31BD50080F1EE /* extra2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra2.c; path = Files/extra2.c; sourceTree = ""; }; + 8E7574BA09F31BD50080F1EE /* float.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = float.c; path = Files/float.c; sourceTree = ""; }; + 8E7574BB09F31BD50080F1EE /* md5.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = md5.c; path = Files/md5.c; sourceTree = ""; }; + 8E7574BC09F31BD50080F1EE /* metadata.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = metadata.c; path = Files/metadata.c; sourceTree = ""; }; + 8E7574BD09F31BD50080F1EE /* pack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pack.c; path = Files/pack.c; sourceTree = ""; }; + 8E7574BE09F31BD50080F1EE /* unpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack.c; path = Files/unpack.c; sourceTree = ""; }; + 8E7574BF09F31BD50080F1EE /* unpack3.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack3.c; path = Files/unpack3.c; sourceTree = ""; }; + 8E7574C009F31BD50080F1EE /* utils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = utils.c; path = Files/utils.c; sourceTree = ""; }; + 8E7574C109F31BD50080F1EE /* wavpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wavpack.c; path = Files/wavpack.c; sourceTree = ""; }; + 8E7574C209F31BD50080F1EE /* words.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = words.c; path = Files/words.c; sourceTree = ""; }; + 8E7574C309F31BD50080F1EE /* wputils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wputils.c; path = Files/wputils.c; sourceTree = ""; }; + 8E7574C409F31BD50080F1EE /* wvunpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wvunpack.c; path = Files/wvunpack.c; sourceTree = ""; }; + 8E7574F409F31C7D0080F1EE /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = /usr/lib/libiconv.dylib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DC2EF560486A6940098B216 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E7574F509F31C7D0080F1EE /* libiconv.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DFFF38A50411DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 8DC2EF5B0486A6940098B216 /* WavPack.framework */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* WavPack */ = { + isa = PBXGroup; + children = ( + 8E7574A909F31B9A0080F1EE /* Headers */, + 8E7574A809F31B940080F1EE /* Source */, + 089C1665FE841158C02AAC07 /* Resources */, + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + 034768DFFF38A50411DB9C8B /* Products */, + ); + name = WavPack; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */, + 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C1665FE841158C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 8DC2EF5A0486A6940098B216 /* Info.plist */, + 089C1666FE841158C02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 8E7574F409F31C7D0080F1EE /* libiconv.dylib */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 8E7574A809F31B940080F1EE /* Source */ = { + isa = PBXGroup; + children = ( + 8E7574B709F31BD50080F1EE /* bits.c */, + 8E7574B809F31BD50080F1EE /* extra1.c */, + 8E7574B909F31BD50080F1EE /* extra2.c */, + 8E7574BA09F31BD50080F1EE /* float.c */, + 8E7574BB09F31BD50080F1EE /* md5.c */, + 8E7574BC09F31BD50080F1EE /* metadata.c */, + 8E7574BD09F31BD50080F1EE /* pack.c */, + 8E7574BE09F31BD50080F1EE /* unpack.c */, + 8E7574BF09F31BD50080F1EE /* unpack3.c */, + 8E7574C009F31BD50080F1EE /* utils.c */, + 8E7574C109F31BD50080F1EE /* wavpack.c */, + 8E7574C209F31BD50080F1EE /* words.c */, + 8E7574C309F31BD50080F1EE /* wputils.c */, + 8E7574C409F31BD50080F1EE /* wvunpack.c */, + ); + name = Source; + sourceTree = ""; + }; + 8E7574A909F31B9A0080F1EE /* Headers */ = { + isa = PBXGroup; + children = ( + 8E7574AF09F31BB90080F1EE /* md5.h */, + 8E7574B009F31BB90080F1EE /* unpack3.h */, + 8E7574B109F31BB90080F1EE /* wavpack.h */, + 8E7574B209F31BB90080F1EE /* wputils.h */, + ); + name = Headers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8DC2EF500486A6940098B216 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E7574B309F31BB90080F1EE /* md5.h in Headers */, + 8E7574B409F31BB90080F1EE /* unpack3.h in Headers */, + 8E7574B509F31BB90080F1EE /* wavpack.h in Headers */, + 8E7574B609F31BB90080F1EE /* wputils.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8DC2EF4F0486A6940098B216 /* WavPack */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "WavPack" */; + buildPhases = ( + 8DC2EF500486A6940098B216 /* Headers */, + 8DC2EF520486A6940098B216 /* Resources */, + 8DC2EF540486A6940098B216 /* Sources */, + 8DC2EF560486A6940098B216 /* Frameworks */, + ); + buildRules = ( + ); + buildSettings = { + }; + dependencies = ( + ); + name = WavPack; + productInstallPath = "$(HOME)/Library/Frameworks"; + productName = WavPack; + productReference = 8DC2EF5B0486A6940098B216 /* WavPack.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "WavPack" */; + buildSettings = { + }; + buildStyles = ( + 014CEA440018CDF011CA2923 /* Debug */, + 014CEA450018CDF011CA2923 /* Release */, + ); + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* WavPack */; + productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; + projectDirPath = ""; + targets = ( + 8DC2EF4F0486A6940098B216 /* WavPack */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8DC2EF520486A6940098B216 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DC2EF540486A6940098B216 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8E7574C509F31BD50080F1EE /* bits.c in Sources */, + 8E7574C609F31BD50080F1EE /* extra1.c in Sources */, + 8E7574C709F31BD50080F1EE /* extra2.c in Sources */, + 8E7574C809F31BD50080F1EE /* float.c in Sources */, + 8E7574C909F31BD50080F1EE /* md5.c in Sources */, + 8E7574CA09F31BD50080F1EE /* metadata.c in Sources */, + 8E7574CB09F31BD50080F1EE /* pack.c in Sources */, + 8E7574CC09F31BD50080F1EE /* unpack.c in Sources */, + 8E7574CD09F31BD50080F1EE /* unpack3.c in Sources */, + 8E7574CE09F31BD50080F1EE /* utils.c in Sources */, + 8E7574D009F31BD50080F1EE /* words.c in Sources */, + 8E7574D109F31BD50080F1EE /* wputils.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C1667FE841158C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1DEB91AE08733DA50010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Frameworks"; + OTHER_CFLAGS = ( + "-DPACK", + "-DUNPACK", + "-DUSE_FSTREAMS", + "-DTAGS", + "-DSEEKING", + "-DVER3", + "-DPACKAGE_NAME=wavpack", + "-DPACKAGE_TARNAME=wavpack", + "-DPACKAGE_VERSION=4.2", + "-DPACKAGE_STRING=\"wavpack 4.2\"", + "-DPACKAGE_BUGREPORT=bryant@wavpack.com", + "-DVERSION_OS=Darwin", + ); + PRODUCT_NAME = WavPack; + WRAPPER_EXTENSION = framework; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB91AF08733DA50010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "@executable_path/../Frameworks"; + OTHER_CFLAGS = ( + "-DPACK", + "-DUNPACK", + "-DUSE_FSTREAMS", + "-DTAGS", + "-DSEEKING", + "-DVER3", + "-DPACKAGE_NAME=wavpack", + "-DPACKAGE_TARNAME=wavpack", + "-DPACKAGE_VERSION=4.2", + "-DPACKAGE_STRING=\"wavpack 4.2\"", + "-DPACKAGE_BUGREPORT=bryant@wavpack.com", + "-DVERSION_OS=Darwin", + ); + PRODUCT_NAME = WavPack; + WRAPPER_EXTENSION = framework; + }; + name = Release; + }; + 1DEB91B208733DA50010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Debug; + }; + 1DEB91B308733DA50010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "WavPack" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91AE08733DA50010E9CD /* Debug */, + 1DEB91AF08733DA50010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "WavPack" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91B208733DA50010E9CD /* Debug */, + 1DEB91B308733DA50010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +}