pax_global_header00006660000000000000000000000064122250246510014511gustar00rootroot0000000000000052 comment=aa61823432218fb6143a688aae1ed694d21889c9 taglib-1.9.1/000077500000000000000000000000001222502465100127635ustar00rootroot00000000000000taglib-1.9.1/.gitignore000066400000000000000000000012731222502465100147560ustar00rootroot00000000000000cmake_install.cmake cmake_uninstall.cmake Makefile CTestTestfile.cmake CMakeFiles/ *.so *.so.* *.dylib *.vcproj *.ncb *.sln *.suo *.user .* *~ /CMakeCache.txt /Doxyfile /config.h /taglib.pc /tests/test_runner /tests/Testing /taglib_config.h /taglib-config /bindings/c/taglib_c.pc /bindings/c/Debug /bindings/c/MinSizeRel /bindings/c/Release /bindings/c/tag_c.dir/Debug /bindings/c/tag_c.dir/MinSizeRel /bindings/c/tag_c.dir/Release /examples/framelist /examples/strip-id3v1 /examples/tagreader /examples/tagreader_c /examples/tagwriter /doc/html /taglib/Debug /taglib/MinSizeRel /taglib/Release /taglib/tag.dir/Debug /taglib/tag.dir/MinSizeRel /taglib/tag.dir/Release /ALL_BUILD.dir /ZERO_CHECK.dir taglib-1.9.1/.travis.yml000066400000000000000000000002561222502465100150770ustar00rootroot00000000000000language: cpp compiler: - gcc - clang install: sudo apt-get install libcppunit-dev zlib1g-dev script: cmake -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON . && make && make check taglib-1.9.1/AUTHORS000066400000000000000000000012321222502465100140310ustar00rootroot00000000000000Scott Wheeler Author, maintainer Lukas Lalinsky Implementation of multiple new file formats, many bug fixes, maintainer Ismael Orenstein Xing header implementation Allan Sandfeld Jensen FLAC metadata implementation Teemu Tervo Numerous bug reports and fixes Mathias Panzenböck Mod, S3M, IT and XM metadata implementations Tsuda Kageyu A lot of fixes and improvements, i.e. memory copy reduction etc. Please send all patches and questions to taglib-devel@kde.org rather than to individual developers! taglib-1.9.1/CMakeLists.txt000066400000000000000000000112311222502465100155210ustar00rootroot00000000000000project(taglib) cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR) option(ENABLE_STATIC "Make static version of libtag" OFF) if(ENABLE_STATIC) add_definitions(-DTAGLIB_STATIC) set(BUILD_SHARED_LIBS OFF) else() set(BUILD_SHARED_LIBS ON) endif() OPTION(ENABLE_STATIC_RUNTIME "Visual Studio, link with runtime statically" OFF) option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF) if(VISIBILITY_HIDDEN) add_definitions (-fvisibility=hidden) endif() option(BUILD_TESTS "Build the test suite" OFF) option(BUILD_EXAMPLES "Build the examples" OFF) option(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF) add_definitions(-DHAVE_CONFIG_H) set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/") ## the following are directories where stuff will be installed to set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") set(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries" FORCE) set(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The subdirectory to the binaries prefix (default prefix/bin)" FORCE) set(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix" FORCE) if(APPLE) option(BUILD_FRAMEWORK "Build an OS X framework" OFF) set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.") endif() if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") endif() if (MSVC AND ENABLE_STATIC_RUNTIME) foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endforeach(flag_var) endif() set(TAGLIB_LIB_MAJOR_VERSION "1") set(TAGLIB_LIB_MINOR_VERSION "9") set(TAGLIB_LIB_PATCH_VERSION "1") set(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}") # 1. If the library source code has changed at all since the last update, then increment revision. # 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0. # 3. If any interfaces have been added since the last public release, then increment age. # 4. If any interfaces have been removed since the last public release, then set age to 0. set(TAGLIB_SOVERSION_CURRENT 15) set(TAGLIB_SOVERSION_REVISION 0) set(TAGLIB_SOVERSION_AGE 14) math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}") math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}") math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}") include(ConfigureChecks.cmake) if(NOT WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib-config ) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/taglib-config DESTINATION ${BIN_INSTALL_DIR}) endif() if(WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmd.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd ) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd DESTINATION ${BIN_INSTALL_DIR}) endif() if(NOT WIN32 AND NOT BUILD_FRAMEWORK) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib.pc ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) endif() include_directories(${CMAKE_CURRENT_BINARY_DIR}) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) if(WITH_ASF) set(TAGLIB_WITH_ASF TRUE) endif() if(WITH_MP4) set(TAGLIB_WITH_MP4 TRUE) endif() option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF) if(TRACE_IN_RELEASE) set(TRACE_IN_RELEASE TRUE) endif() configure_file(taglib/taglib_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h) add_subdirectory(taglib) add_subdirectory(bindings) if(BUILD_TESTS) enable_testing() add_subdirectory(tests) endif(BUILD_TESTS) add_subdirectory(examples) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) file(COPY doc/taglib.png DESTINATION doc) add_custom_target(docs doxygen) # uninstall target configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") taglib-1.9.1/COPYING.LGPL000066400000000000000000000636421222502465100145660ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. 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 combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 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.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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! taglib-1.9.1/COPYING.MPL000066400000000000000000000622331222502465100144530ustar00rootroot00000000000000 MOZILLA PUBLIC LICENSE Version 1.1 --------------- 1. Definitions. 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. 1.5. "Executable" means Covered Code in any form other than Source Code. 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. 1.8. "License" means this document. 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. Source Code License. 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. 3.4. Intellectual Property Matters (a) Third Party Claims. If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. (b) Contributor APIs. If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. (c) Representations. Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. 4. Inability to Comply Due to Statute or Regulation. If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Application of this License. This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. 6. Versions of the License. 6.1. New Versions. Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. 6.2. Effect of New Versions. Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. 6.3. Derivative Works. If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", "NPL" or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) 7. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 8. TERMINATION. 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: (a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. (b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 10. U.S. GOVERNMENT END USERS. The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. 11. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. 12. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. 13. MULTIPLE-LICENSED CODE. Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the NPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. EXHIBIT A -Mozilla Public License. ``The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is ______________________________________. The Initial Developer of the Original Code is ________________________. Portions created by ______________________ are Copyright (C) ______ _______________________. All Rights Reserved. Contributor(s): ______________________________________. Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] taglib-1.9.1/ConfigureChecks.cmake000066400000000000000000000123011222502465100170240ustar00rootroot00000000000000include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckCXXSourceCompiles) include(TestBigEndian) # Check if the size of integral types are suitable. check_type_size("short" SIZEOF_SHORT) if(NOT ${SIZEOF_SHORT} EQUAL 2) MESSAGE(FATAL_ERROR "TagLib requires that short is 16-bit wide.") endif() check_type_size("int" SIZEOF_INT) if(NOT ${SIZEOF_INT} EQUAL 4) MESSAGE(FATAL_ERROR "TagLib requires that int is 32-bit wide.") endif() check_type_size("long long" SIZEOF_LONGLONG) if(NOT ${SIZEOF_LONGLONG} EQUAL 8) MESSAGE(FATAL_ERROR "TagLib requires that long long is 64-bit wide.") endif() check_type_size("wchar_t" SIZEOF_WCHAR_T) if(${SIZEOF_WCHAR_T} LESS 2) MESSAGE(FATAL_ERROR "TagLib requires that wchar_t is sufficient to store a UTF-16 char.") endif() # Determine the CPU byte order. test_big_endian(IS_BIG_ENDIAN) if(NOT IS_BIG_ENDIAN) set(SYSTEM_BYTEORDER 1) else() set(SYSTEM_BYTEORDER 2) endif() # Determine which kind of atomic operations your compiler supports. check_cxx_source_compiles(" #include int main() { std::atomic x; x.fetch_add(1); x.fetch_sub(1); return 0; } " HAVE_STD_ATOMIC) if(NOT HAVE_STD_ATOMIC) check_cxx_source_compiles(" #include int main() { boost::atomic x(1); x.fetch_add(1); x.fetch_sub(1); return 0; } " HAVE_BOOST_ATOMIC) if(NOT HAVE_BOOST_ATOMIC) check_cxx_source_compiles(" int main() { volatile int x; __sync_add_and_fetch(&x, 1); int y = __sync_sub_and_fetch(&x, 1); return 0; } " HAVE_GCC_ATOMIC) if(NOT HAVE_GCC_ATOMIC) check_cxx_source_compiles(" #include int main() { volatile int32_t x; OSAtomicIncrement32Barrier(&x); int32_t y = OSAtomicDecrement32Barrier(&x); return 0; } " HAVE_MAC_ATOMIC) if(NOT HAVE_MAC_ATOMIC) check_cxx_source_compiles(" #include int main() { volatile LONG x; InterlockedIncrement(&x); LONG y = InterlockedDecrement(&x); return 0; } " HAVE_WIN_ATOMIC) if(NOT HAVE_WIN_ATOMIC) check_cxx_source_compiles(" #include int main() { volatile int x; __sync_add_and_fetch(&x, 1); int y = __sync_sub_and_fetch(&x, 1); return 0; } " HAVE_IA64_ATOMIC) endif() endif() endif() endif() endif() # Determine which kind of byte swap functions your compiler supports. # GCC's __builtin_bswap* should be checked individually # because some of them can be missing depends on the GCC version. check_cxx_source_compiles(" int main() { __builtin_bswap16(0); return 0; } " HAVE_GCC_BYTESWAP_16) check_cxx_source_compiles(" int main() { __builtin_bswap32(0); return 0; } " HAVE_GCC_BYTESWAP_32) check_cxx_source_compiles(" int main() { __builtin_bswap64(0); return 0; } " HAVE_GCC_BYTESWAP_64) if(NOT HAVE_GCC_BYTESWAP_16 OR NOT HAVE_GCC_BYTESWAP_32 OR NOT HAVE_GCC_BYTESWAP_64) check_cxx_source_compiles(" #include int main() { __bswap_16(0); __bswap_32(0); __bswap_64(0); return 0; } " HAVE_GLIBC_BYTESWAP) if(NOT HAVE_GLIBC_BYTESWAP) check_cxx_source_compiles(" #include int main() { _byteswap_ushort(0); _byteswap_ulong(0); _byteswap_uint64(0); return 0; } " HAVE_MSC_BYTESWAP) if(NOT HAVE_MSC_BYTESWAP) check_cxx_source_compiles(" #include int main() { OSSwapInt16(0); OSSwapInt32(0); OSSwapInt64(0); return 0; } " HAVE_MAC_BYTESWAP) if(NOT HAVE_MAC_BYTESWAP) check_cxx_source_compiles(" #include int main() { swap16(0); swap32(0); swap64(0); return 0; } " HAVE_OPENBSD_BYTESWAP) endif() endif() endif() endif() # Determine whether your compiler supports some safer version of sprintf. check_cxx_source_compiles(" #include int main() { char buf[20]; snprintf(buf, 20, \"%d\", 1); return 0; } " HAVE_SNPRINTF) if(NOT HAVE_SNPRINTF) check_cxx_source_compiles(" #include int main() { char buf[20]; sprintf_s(buf, \"%d\", 1); return 0; } " HAVE_SPRINTF_S) endif() # Determine whether your compiler supports codecvt. check_cxx_source_compiles(" #include int main() { std::codecvt_utf8_utf16 x; return 0; } " HAVE_STD_CODECVT) # Check for libz using the cmake supplied FindZLIB.cmake find_package(ZLIB) if(ZLIB_FOUND) set(HAVE_ZLIB 1) else() set(HAVE_ZLIB 0) endif() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) if(NOT CppUnit_FOUND AND BUILD_TESTS) message(STATUS "CppUnit not found, disabling tests.") set(BUILD_TESTS OFF) endif() taglib-1.9.1/Doxyfile.cmake000066400000000000000000000200001222502465100155400ustar00rootroot00000000000000# Doxyfile 1.3.4 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = TagLib PROJECT_NUMBER = ${TAGLIB_LIB_VERSION_STRING} OUTPUT_DIRECTORY = doc OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = YES CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO GENERATE_DEPRECATEDLIST= NO ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = @CMAKE_SOURCE_DIR@/taglib FILE_PATTERNS = *.h \ *.hh \ *.H RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = @CMAKE_SOURCE_DIR@/doc/api-header.html HTML_FOOTER = @CMAKE_SOURCE_DIR@/doc/api-footer.html HTML_STYLESHEET = @CMAKE_SOURCE_DIR@/doc/taglib-api.css HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = YES ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = letter EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DO_NOT_DOCUMENT \ DOXYGEN \ WITH_MP4 \ WITH_ASF EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES UML_LOOK = NO TEMPLATE_RELATIONS = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 0 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO taglib-1.9.1/INSTALL000066400000000000000000000125051222502465100140170ustar00rootroot00000000000000TagLib Installation =================== TagLib uses the CMake build system. As a user, you will most likely want to build TagLib in release mode and install it into a system-wide location. This can be done using the following commands: cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_RELEASE_TYPE=Release . make sudo make install In order to build the included examples, use the BUILD_EXAMPLES option: cmake -DBUILD_EXAMPLES=ON [...] See http://www.cmake.org/cmake/help/runningcmake.html for generic help on running CMake. Mac OS X -------- On Mac OS X, you might want to build a framework that can be easily integrated into your application. If you set the BUILD_FRAMEWORK option on, it will compile TagLib as a framework. For example, the following command can be used to build an Universal Binary framework with Mac OS X 10.4 as the deployment target: cmake -DCMAKE_BUILD_TYPE=Release \ -DBUILD_FRAMEWORK=ON \ -DCMAKE_C_COMPILER=/usr/bin/gcc-4.0 \ -DCMAKE_CXX_COMPILER=/usr/bin/c++-4.0 \ -DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.4u.sdk/ \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.4 \ -DCMAKE_OSX_ARCHITECTURES="ppc;i386;x86_64" For a 10.6 Snow Leopard static library with both 32-bit and 64-bit code, use: cmake -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.6 \ -DCMAKE_OSX_ARCHITECTURES="i386;x86_64" \ -DENABLE_STATIC=ON \ -DCMAKE_INSTALL_PREFIX="" After 'make', and 'make install', add libtag.a to your XCode project, and add the include folder to the project's User Header Search Paths. Windows ------- It's Windows ... Systems vary! This means you need to adjust things to suit your system, especially paths. Tested with: Microsoft Visual Studio 2010 Gcc by mingw-w64.sf.net v4.6.3 (Strawberry Perl 32b) MinGW32-4.8.0 Requirements: 1. Tool chain, Build Environment, Whatever ya want to call it ... Installed and working. 2. CMake program. (Available at: www.cmake.org) Installed and working. Optional: 1. Zlib library. Available in some Tool Chains, Not all. Search the web, Take your choice. Useful configuration options used with CMake (GUI and/or Command line): Any of the ZLIB_ variables may be used at the command line, ZLIB_ROOT is only available on the Command line. ZLIB_ROOT= Where to find ZLib's root directory. Assumes parent of: \include and \lib. ZLIB_INCLUDE_DIR= Where to find ZLib's Include directory. ZLIB_LIBRARY= Where to find ZLib's Library. CMAKE_INSTALL_PREFIX= Where to install Taglib. CMAKE_BUILD_TYPE= Release, Debug, etc ... (Not available in MSVC) The easiest way is at the Command Prompt. MSVS Command Prompt for MSVS Users. (Batch file and/or Shortcuts are your friends) 1. Build the Makefiles: Replace "GENERATOR" with your needs. For MSVS : "Visual Studio X" where X is the single or two digit version. For MinGW: "MinGW Makefiles" C:\GitRoot\taglib> cmake -G "GENERATOR" -DCMAKE_INSTALL_PREFIX=C:\Libraries\taglib Or use the CMake GUI: 1. Open CMake GUI. 2. Set Paths. "Where is the source code" and "Where to build the binaries" Example, Both would be: C:\GitRoot\taglib 3. Tick: Advanced 4. Select: Configure 5. Select: Generator 6. Tick: Use default native compilers 7. Select: Finish Wait until done. 5. If using ZLib, Scroll down. (to the bottom of the list of options ... should go over them all) 1. Edit: ZLIB_INCLUDE_DIR 2. Edit: ZLIB_LIBRARY 6. Select: Generate 2. Build the project: MSVS: C:\GitRoot\taglib> msbuild all_build.vcxproj /p:Configuration=Release OR (Depending on MSVS version or personal choice) C:\GitRoot\taglib> devenv all_build.vcxproj /build Release MinGW: C:\GitRoot\taglib> gmake OR (Depending on MinGW install) C:\GitRoot\taglib> mingw32-make Or in the MSVS GUI: 1. Open MSVS. 2. Open taglib solution. 3. Set build type to: Release (look in the tool bars) 2. Hit F7 to build the solution. (project) 3. Install the project: (Change 'install' to 'uninstall' to uninstall the project) MSVS: C:\GitRoot\taglib> msbuild install.vcxproj OR (Depending on MSVC version or personal choice) C:\GitRoot\taglib> devenv install.vcxproj MinGW: C:\GitRoot\taglib> gmake install OR (Depending on MinGW install) C:\GitRoot\taglib> mingw32-make install Or in the MSVS GUI: 1. Open project. 2. Open Solution Explorer. 3. Right Click: INSTALL 4. Select: Project Only 5. Select: Build Only INSTALL To build a static library enable the following two options with CMake. -DENABLE_STATIC=ON -DENABLE_STATIC_RUNTIME=ON Including ENABLE_STATIC_RUNTIME=ON indicates you want TagLib built using the static runtime library, rather than the DLL form of the runtime. Unit Tests ---------- If you want to run the test suite to make sure TagLib works properly on your system, you need to have cppunit installed. To build the tests, include the option -DBUILD_TESTS=on when running cmake. The test suite has a custom target in the build system, so you can run the tests using make: make check taglib-1.9.1/NEWS000066400000000000000000000176451222502465100134770ustar00rootroot00000000000000TagLib 1.9.1 (Oct 8, 2013) ========================== * Fixed binary incompatible change in TagLib::Map and TagLib::List. * Fixed constructing String from ByteVector. * Fixed compilation on MSVC with the /Zc:wchar_t- option. * Fixed detecting of RIFF files with invalid chunk sizes. * Added TagLib::MP4::PropertyMap::codec(). TagLib 1.9 (Oct 6, 2013) ======================== * Added support for the Ogg Opus file format. * Added support for INFO tags in WAV files. * Changed FileStream to use Windows file API. * Included taglib-config.cmd script for Windows. * New ID3v1::Tag methods for working directly with genre numbers. * New MPEG::File methods for checking which tags are saved in the file. * Added support for the PropertyMap API to ASF and MP4 files. * Added MusicBrainz identifiers to the PropertyMap API. * Allowed reading of MP4 cover art without an explicitly specified format. * Better parsing of corrupted FLAC files. * Fixed saving of PropertyMap comments without description into ID3v2 tags. * Fixed crash when parsing certain XM files. * Fixed compilation of unit test with clang. * Better handling of files that can't be open or have read-only permissions. * Improved atomic reference counting. * New hookable API for debug messages. * More complete Windows install instructions. * Many smaller bug fixes and performance improvements. TagLib 1.8 (Sep 6, 2012) ======================== 1.8: * Added support for OWNE ID3 frames. * Changed key validation in the new PropertyMap API. * ID3v1::Tag::setStringHandler will no londer delete the previous handler, the caller is responsible for this. * File objects will also no longer delete the passed IOStream objects. It should be done in the caller code after the File object is no longer used. * Added ID3v2::Tag::setLatin1StringHandler for custom handling of latin1-encoded text in ID3v2 frames. * Fixed validation of ID3v2 frame IDs (IDs with '0' were ignored). 1.8 BETA: * New API for accessing tags by name. * New abstract I/O stream layer to allow custom I/O handlers. * Support for writing ID3v2.3 tags. * Support for various module file formats (MOD, S3M, IT, XM). * Support for MP4 and ASF is now enabled by default. * Started using atomic int operations for reference counting. * Added methods for checking if WMA and MP4 files are DRM-protected. * Added taglib_free to the C bindings. * New method to allow removing pictures from FLAC files. * Support for reading audio properties from ALAC and Musepack SV8 files. * Added replay-gain information to Musepack audio properties. * Support for APEv2 binary tags. * Many AudioProperties subclasses now provide information about the total number of samples. * Various small bug fixes. TagLib 1.7.2 (Apr 20, 2012) =========================== * Fixed division by zero while parsing corrupted MP4 files (CVE-2012-2396). * Fixed compilation on Haiku. TagLib 1.7.1 (Mar 17, 2012) =========================== * Improved parsing of corrupted WMA, RIFF and OGG files. * Fixed a memory leak in the WMA parser. * Fixed a memory leak in the FLAC parser. * Fixed a possible division by zero in the APE parser. * Added detection of TTA2 files. * Fixed saving of multiple identically named tags to Vorbis Comments. TagLib 1.7 (Mar 11, 2011) ========================= 1.7: * Fixed memory leaks in the FLAC file format parser. * Fixed bitrate calculation for WAV files. 1.7 RC1: * Support for reading/writing tags from Monkey's Audio files. (BUG:210404) * Support for reading/writing embedded pictures from WMA files. * Support for reading/writing embedded pictures from FLAC files (BUG:218696). * Implemented APE::Tag::isEmpty() to check for all APE tags, not just the basic ones. * Added reading of WAV audio length. (BUG:116033) * Exposed FLAC MD5 signature of the uncompressed audio stream via FLAC::Properties::signature(). (BUG:160172) * Added function ByteVector::toHex() for hex-encoding of byte vectors. * WavPack reader now tries to get the audio length by finding the final block, if the header doesn't have the information. (BUG:258016) * Fixed a memory leak in the ID3v2.2 PIC frame parser. (BUG:257007) * Fixed writing of RIFF files with even chunk sizes. (BUG:243954) * Fixed compilation on MSVC 2010. * Removed support for building using autoconf/automake. * API docs can be now built using "make docs". TagLib 1.6.3 (Apr 17, 2010) =========================== * Fixed definitions of the TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF macros. * Fixed upgrading of ID3v2.3 genre frame with ID3v1 code 0 (Blues). * New method `int String::toInt(bool *ok)` which can return whether the conversion to a number was successfull. * Fixed parsing of incorrectly written lengths in ID3v2 (affects mainly compressed frames). (BUG:231075) TagLib 1.6.2 (Apr 9, 2010) ========================== * Read Vorbis Comments from the first FLAC metadata block, if there are multipe ones. (BUG:211089) * Fixed a memory leak in FileRef's OGA format detection. * Fixed compilation with the Sun Studio compiler. (BUG:215225) * Handle WM/TrackNumber attributes with DWORD content in WMA files. (BUG:218526) * More strict check if something is a valid MP4 file. (BUG:216819) * Correctly save MP4 int-pair atoms with flags set to 0. * Fixed compilation of the test runner on Windows. * Store ASF attributes larger than 64k in the metadata library object. * Ignore trailing non-data atoms when parsing MP4 covr atoms. * Don't upgrade ID3v2.2 frame TDA to TDRC. (BUG:228968) TagLib 1.6.1 (Oct 31, 2009) =========================== * Better detection of the audio codec of .oga files in FileRef. * Fixed saving of Vorbis comments to Ogg FLAC files. TagLib tried to include the Vorbis framing bit, which is only correct for Ogg Vorbis. * Public symbols now have explicitly set visibility to "default" on GCC. * Added missing exports for static ID3v1 functions. * Fixed a typo in taglib_c.pc * Fixed a failing test on ppc64. * Support for binary 'covr' atom in MP4 files. TagLib 1.6 treated them as text atoms, which corrupted them in some cases. * Fixed ID3v1-style genre to string conversion in MP4 files. TagLib 1.6 (Sep 13, 2009) ========================= 1.6: * New CMake option to build a static version - ENABLE_STATIC. * Added support for disabling dllimport/dllexport on Windows using the TAGLIB_STATIC macro. * Support for parsing the obsolete 'gnre' MP4 atom. * New cpp macros TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF to determin if TagLib was built with MP4/ASF support. 1.6 RC1: * Split Ogg packets larger than 64k into multiple pages. (BUG:171957) * TagLib can now use FLAC padding block. (BUG:107659) * ID3v2.2 frames are now not incorrectly saved. (BUG:176373) * Support for ID3v2.2 PIC frames. (BUG:167786) * Fixed a bug in ByteVectorList::split(). * XiphComment::year() now falls back to YEAR if DATE doesn't exist and XiphComment::year() falls back to TRACKNUM if TRACKNUMBER doesn't exist. (BUG:144396) * Improved ID3v2.3 genre parsing. (BUG:188578) * Better checking of corrupted ID3v2 APIC data. (BUG:168382) * Bitrate calculating using the Xing header now uses floating point numbers. (BUG:172556) * New TagLib::String method rfind(). * Added support for MP4 file format with iTunes-style metadata [optional]. * Added support for ASF (WMA) file format [optional]. * Fixed crash when saving a Locator APEv2 tag. (BUG:169810) * Fixed a possible crash in the non-const version of String::operator[] and in String::operator+=. (BUG:169389) * Added support for PRIV ID3v2 frames. * Empty ID3v2 genres are no longer treated as numeric ID3v1 genres. * Added support for the POPM (rating/playcount) ID3v2 frame. * Generic RIFF file format support: * Support for AIFF files with ID3v2 tags. * Support for WAV files with ID3v2 tags. * Fixed crash on handling unsupported ID3v2 frames, e.g. on encrypted frames. (BUG:161721) * Fixed overflow while calculating bitrate of FLAC files with a very high bitrate. taglib-1.9.1/bindings/000077500000000000000000000000001222502465100145605ustar00rootroot00000000000000taglib-1.9.1/bindings/CMakeLists.txt000066400000000000000000000000251222502465100173150ustar00rootroot00000000000000add_subdirectory(c) taglib-1.9.1/bindings/README000066400000000000000000000004351222502465100154420ustar00rootroot00000000000000There are a few other people that have done bindings externally that I have been made aware of. I have not personally reviewed these bindings, but I'm listing them here so that those who find them useful are able to find them: http://developer.kde.org/~wheeler/taglib.html#bindings taglib-1.9.1/bindings/c/000077500000000000000000000000001222502465100150025ustar00rootroot00000000000000taglib-1.9.1/bindings/c/CMakeLists.txt000066400000000000000000000052611222502465100175460ustar00rootroot00000000000000include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/toolkit ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/asf ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/vorbis ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/flac ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/flac ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpc ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mp4 ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg/id3v2 ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg/id3v2/frames ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/wavpack ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/speex ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/trueaudio ) set(tag_c_HDRS tag_c.h) add_library(tag_c tag_c.cpp ${tag_c_HDRS}) target_link_libraries(tag_c tag) set_target_properties(tag_c PROPERTIES PUBLIC_HEADER "${tag_c_HDRS}") if(BUILD_FRAMEWORK) set_target_properties(tag_c PROPERTIES FRAMEWORK TRUE) endif() # On Solaris we need to explicitly add the C++ standard and runtime # libraries to the libs used by the C bindings, because those C bindings # themselves won't pull in the C++ libs -- and if a C application is # using the C bindings then we get link errors. check_library_exists(Crun __RTTI___ "" HAVE_CRUN_LIB) if(HAVE_CRUN_LIB) # Which libraries to link depends critically on which # STL version is going to be used by your application # and which runtime is in use. While Crun is pretty much # the only game in town, the three available STLs -- Cstd, # stlport4 and stdcxx -- make this a mess. The KDE-Solaris # team supports stdcxx (Apache RogueWave stdcxx 4.1.3). # According to http://bugs.kde.org/show_bug.cgi?id=215225 the library can have the following two names: find_library(ROGUEWAVE_STDCXX_LIBRARY NAMES stdcxx4 stdcxx) if(NOT ROGUEWAVE_STDCXX_LIBRARY) message(FATAL_ERROR "Did not find supported STL library (tried stdcxx4 and stdcxx)") endif() target_link_libraries(tag_c ${ROGUEWAVE_STDCXX_LIBRARY} Crun) endif() set_target_properties(tag_c PROPERTIES VERSION 0.0.0 SOVERSION 0 DEFINE_SYMBOL MAKE_TAGLIB_C_LIB INSTALL_NAME_DIR ${LIB_INSTALL_DIR} ) install(TARGETS tag_c FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION ${BIN_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib ) if(NOT WIN32 AND NOT BUILD_FRAMEWORK) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) endif() taglib-1.9.1/bindings/c/tag_c.cpp000066400000000000000000000210731222502465100165660ustar00rootroot00000000000000/*************************************************************************** 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 #include #include #include #include #include #include #include #include #include #include #include #include "tag_c.h" using namespace TagLib; static List strings; static bool unicodeStrings = true; static bool stringManagementEnabled = true; void taglib_set_strings_unicode(BOOL unicode) { unicodeStrings = bool(unicode); } void taglib_set_string_management_enabled(BOOL management) { stringManagementEnabled = bool(management); } void taglib_free(void* pointer) { free(pointer); } //////////////////////////////////////////////////////////////////////////////// // 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 Ogg::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)); case TagLib_File_OggFlac: return reinterpret_cast(new Ogg::FLAC::File(filename)); case TagLib_File_WavPack: return reinterpret_cast(new WavPack::File(filename)); case TagLib_File_Speex: return reinterpret_cast(new Ogg::Speex::File(filename)); case TagLib_File_TrueAudio: return reinterpret_cast(new TrueAudio::File(filename)); case TagLib_File_MP4: return reinterpret_cast(new MP4::File(filename)); case TagLib_File_ASF: return reinterpret_cast(new ASF::File(filename)); default: return 0; } return 0; } void taglib_file_free(TagLib_File *file) { delete reinterpret_cast(file); } BOOL taglib_file_is_valid(const TagLib_File *file) { return reinterpret_cast(file)->isValid(); } 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) free(*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(); } void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding) { String::Type type = String::Latin1; switch(encoding) { case TagLib_ID3v2_Latin1: type = String::Latin1; break; case TagLib_ID3v2_UTF16: type = String::UTF16; break; case TagLib_ID3v2_UTF16BE: type = String::UTF16BE; break; case TagLib_ID3v2_UTF8: type = String::UTF8; break; } ID3v2::FrameFactory::instance()->setDefaultTextEncoding(type); } taglib-1.9.1/bindings/c/tag_c.h000066400000000000000000000227731222502465100162430ustar00rootroot00000000000000/*************************************************************************** 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 #if defined(TAGLIB_STATIC) #define TAGLIB_C_EXPORT #elif defined(_WIN32) || defined(_WIN64) #ifdef MAKE_TAGLIB_C_LIB #define TAGLIB_C_EXPORT __declspec(dllexport) #else #define TAGLIB_C_EXPORT __declspec(dllimport) #endif #elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1) #define TAGLIB_C_EXPORT __attribute__ ((visibility("default"))) #else #define TAGLIB_C_EXPORT #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 corresponding 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. */ TAGLIB_C_EXPORT 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. */ TAGLIB_C_EXPORT void taglib_set_string_management_enabled(BOOL management); /*! * Explicitly free a string returned from TagLib */ TAGLIB_C_EXPORT void taglib_free(void* pointer); /******************************************************************************* * File API ******************************************************************************/ typedef enum { TagLib_File_MPEG, TagLib_File_OggVorbis, TagLib_File_FLAC, TagLib_File_MPC, TagLib_File_OggFlac, TagLib_File_WavPack, TagLib_File_Speex, TagLib_File_TrueAudio, TagLib_File_MP4, TagLib_File_ASF } 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_C_EXPORT 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_C_EXPORT TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type); /*! * Frees and closes the file. */ TAGLIB_C_EXPORT void taglib_file_free(TagLib_File *file); /*! * Returns true if the file is open and readble and valid information for * the Tag and / or AudioProperties was found. */ TAGLIB_C_EXPORT BOOL taglib_file_is_valid(const TagLib_File *file); /*! * Returns a pointer to the tag associated with this file. This will be freed * automatically when the file is freed. */ TAGLIB_C_EXPORT 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. */ TAGLIB_C_EXPORT const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file); /*! * Saves the \a file to disk. */ TAGLIB_C_EXPORT 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(). */ TAGLIB_C_EXPORT 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(). */ TAGLIB_C_EXPORT 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(). */ TAGLIB_C_EXPORT 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(). */ TAGLIB_C_EXPORT 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(). */ TAGLIB_C_EXPORT char *taglib_tag_genre(const TagLib_Tag *tag); /*! * Returns the tag's year or 0 if year is not set. */ TAGLIB_C_EXPORT unsigned int taglib_tag_year(const TagLib_Tag *tag); /*! * Returns the tag's track number or 0 if track number is not set. */ TAGLIB_C_EXPORT unsigned int taglib_tag_track(const TagLib_Tag *tag); /*! * Sets the tag's title. * * \note By default this string should be UTF8 encoded. */ TAGLIB_C_EXPORT 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. */ TAGLIB_C_EXPORT 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. */ TAGLIB_C_EXPORT 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. */ TAGLIB_C_EXPORT 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. */ TAGLIB_C_EXPORT void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre); /*! * Sets the tag's year. 0 indicates that this field should be cleared. */ TAGLIB_C_EXPORT 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. */ TAGLIB_C_EXPORT void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track); /*! * Frees all of the strings that have been created by the tag. */ TAGLIB_C_EXPORT void taglib_tag_free_strings(void); /****************************************************************************** * Audio Properties API ******************************************************************************/ /*! * Returns the length of the file in seconds. */ TAGLIB_C_EXPORT int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties); /*! * Returns the bitrate of the file in kb/s. */ TAGLIB_C_EXPORT int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties); /*! * Returns the sample rate of the file in Hz. */ TAGLIB_C_EXPORT int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties); /*! * Returns the number of channels in the audio stream. */ TAGLIB_C_EXPORT int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties); /******************************************************************************* * Special convenience ID3v2 functions *******************************************************************************/ typedef enum { TagLib_ID3v2_Latin1, TagLib_ID3v2_UTF16, TagLib_ID3v2_UTF16BE, TagLib_ID3v2_UTF8 } TagLib_ID3v2_Encoding; /*! * This sets the default encoding for ID3v2 frames that are written to tags. */ TAGLIB_C_EXPORT void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding); #ifdef __cplusplus } #endif #endif /* DO_NOT_DOCUMENT */ #endif taglib-1.9.1/bindings/c/taglib_c.pc.cmake000066400000000000000000000006051222502465100201520ustar00rootroot00000000000000prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${LIB_INSTALL_DIR} includedir=${INCLUDE_INSTALL_DIR} Name: TagLib C Bindings Description: Audio meta-data library (C bindings) Requires: taglib Version: ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION} Libs: -L${LIB_INSTALL_DIR} -ltag_c Cflags: -I${INCLUDE_INSTALL_DIR}/taglib taglib-1.9.1/cmake/000077500000000000000000000000001222502465100140435ustar00rootroot00000000000000taglib-1.9.1/cmake/modules/000077500000000000000000000000001222502465100155135ustar00rootroot00000000000000taglib-1.9.1/cmake/modules/FindCppUnit.cmake000066400000000000000000000052231222502465100207020ustar00rootroot00000000000000# - Try to find the libcppunit libraries # Once done this will define # # CppUnit_FOUND - system has libcppunit # CPPUNIT_INCLUDE_DIR - the libcppunit include directory # CPPUNIT_LIBRARIES - libcppunit library include (MacroEnsureVersion) if(NOT CPPUNIT_MIN_VERSION) SET(CPPUNIT_MIN_VERSION 1.12.0) endif(NOT CPPUNIT_MIN_VERSION) FIND_PROGRAM(CPPUNIT_CONFIG_EXECUTABLE cppunit-config ) IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) # in cache already SET(CppUnit_FOUND TRUE) ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CPPUNIT_INCLUDE_DIR) SET(CPPUNIT_LIBRARIES) IF(CPPUNIT_CONFIG_EXECUTABLE) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_CFLAGS) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_LIBRARIES) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) STRING(REGEX REPLACE "-I(.+)" "\\1" CPPUNIT_CFLAGS "${CPPUNIT_CFLAGS}") ELSE(CPPUNIT_CONFIG_EXECUTABLE) # in case win32 needs to find it the old way? FIND_PATH(CPPUNIT_CFLAGS cppunit/TestRunner.h PATHS /usr/include /usr/local/include ) FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib ) # how can we find cppunit version? MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}") SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION}) ENDIF(CPPUNIT_CONFIG_EXECUTABLE) SET(CPPUNIT_INCLUDE_DIR ${CPPUNIT_CFLAGS} "${CPPUNIT_CFLAGS}/cppunit") ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CppUnit_FOUND TRUE) if(NOT CppUnit_FIND_QUIETLY) MESSAGE (STATUS "Found cppunit: ${CPPUNIT_LIBRARIES}") endif(NOT CppUnit_FIND_QUIETLY) IF(CPPUNIT_CONFIG_EXECUTABLE) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) ENDIF(CPPUNIT_CONFIG_EXECUTABLE) macro_ensure_version( ${CPPUNIT_MIN_VERSION} ${CPPUNIT_INSTALLED_VERSION} CPPUNIT_INSTALLED_VERSION_OK ) IF(NOT CPPUNIT_INSTALLED_VERSION_OK) MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or major is required") SET(CppUnit_FOUND FALSE) ENDIF(NOT CPPUNIT_INSTALLED_VERSION_OK) ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CppUnit_FOUND FALSE CACHE BOOL "Not found cppunit library") ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARIES) taglib-1.9.1/cmake/modules/MacroEnsureVersion.cmake000066400000000000000000000066561222502465100223230ustar00rootroot00000000000000# This macro compares version numbers of the form "x.y.z" # MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK) # will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION # where both have to be in a 3-part-version format, leading and trailing # text is ok, e.g. # MACRO_ENSURE_VERSION( "2.5.31" "flex 2.5.4a" VERSION_OK) # which means 2.5.31 is required and "flex 2.5.4a" is what was found on the system # Copyright (c) 2006, David Faure, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO(MACRO_ENSURE_VERSION requested_version found_version var_too_old) # parse the parts of the version string STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" req_major_vers "${requested_version}") STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" req_minor_vers "${requested_version}") STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" req_patch_vers "${requested_version}") STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" found_major_vers "${found_version}") STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" found_minor_vers "${found_version}") STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" found_patch_vers "${found_version}") # compute an overall version number which can be compared at once MATH(EXPR req_vers_num "${req_major_vers}*10000 + ${req_minor_vers}*100 + ${req_patch_vers}") MATH(EXPR found_vers_num "${found_major_vers}*10000 + ${found_minor_vers}*100 + ${found_patch_vers}") if (found_vers_num LESS req_vers_num) set( ${var_too_old} FALSE ) else (found_vers_num LESS req_vers_num) set( ${var_too_old} TRUE ) endif (found_vers_num LESS req_vers_num) ENDMACRO(MACRO_ENSURE_VERSION) # This macro compares version numbers of the form "x.y" # MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK) # will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION # where both have to be in a 2-part-version format, leading and trailing # text is ok, e.g. # MACRO_ENSURE_VERSION( "0.5" "foo 0.6" VERSION_OK) # which means 0.5 is required and "foo 0.6" is what was found on the system # Copyright (c) 2006, David Faure, # Copyright (c) 2007, Pino Toscano, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO(MACRO_ENSURE_VERSION2 requested_version found_version var_too_old) # parse the parts of the version string STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+" "\\1" req_major_vers "${requested_version}") STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)" "\\1" req_minor_vers "${requested_version}") STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+.*" "\\1" found_major_vers "${found_version}") STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+).*" "\\1" found_minor_vers "${found_version}") # compute an overall version number which can be compared at once MATH(EXPR req_vers_num "${req_major_vers}*100 + ${req_minor_vers}") MATH(EXPR found_vers_num "${found_major_vers}*100 + ${found_minor_vers}") if (found_vers_num LESS req_vers_num) set( ${var_too_old} FALSE ) else (found_vers_num LESS req_vers_num) set( ${var_too_old} TRUE ) endif (found_vers_num LESS req_vers_num) ENDMACRO(MACRO_ENSURE_VERSION2) taglib-1.9.1/cmake_uninstall.cmake.in000066400000000000000000000014271222502465100175470ustar00rootroot00000000000000if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") endif() file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach (file ${files}) message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") if (EXISTS "$ENV{DESTDIR}${file}") execute_process( COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" OUTPUT_VARIABLE rm_out RESULT_VARIABLE rm_retval ) if(NOT ${rm_retval} EQUAL 0) message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") endif () else () message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") endif () endforeach() taglib-1.9.1/config.h.cmake000066400000000000000000000022761222502465100154670ustar00rootroot00000000000000/* config.h. Generated by cmake from config.h.cmake */ /* Indicates the byte order of your target system */ /* 1 if little-endian, 2 if big-endian. */ #cmakedefine SYSTEM_BYTEORDER ${SYSTEM_BYTEORDER} /* Defined if your compiler supports some byte swap functions */ #cmakedefine HAVE_GCC_BYTESWAP_16 1 #cmakedefine HAVE_GCC_BYTESWAP_32 1 #cmakedefine HAVE_GCC_BYTESWAP_64 1 #cmakedefine HAVE_GLIBC_BYTESWAP 1 #cmakedefine HAVE_MSC_BYTESWAP 1 #cmakedefine HAVE_MAC_BYTESWAP 1 #cmakedefine HAVE_OPENBSD_BYTESWAP 1 /* Defined if your compiler supports codecvt */ #cmakedefine HAVE_STD_CODECVT 1 /* Defined if your compiler supports some atomic operations */ #cmakedefine HAVE_STD_ATOMIC 1 #cmakedefine HAVE_BOOST_ATOMIC 1 #cmakedefine HAVE_GCC_ATOMIC 1 #cmakedefine HAVE_MAC_ATOMIC 1 #cmakedefine HAVE_WIN_ATOMIC 1 #cmakedefine HAVE_IA64_ATOMIC 1 /* Defined if your compiler supports some safer version of sprintf */ #cmakedefine HAVE_SNPRINTF 1 #cmakedefine HAVE_SPRINTF_S 1 /* Defined if you have libz */ #cmakedefine HAVE_ZLIB 1 /* Indicates whether debug messages are shown even in release mode */ #cmakedefine TRACE_IN_RELEASE 1 #cmakedefine TESTS_DIR "@TESTS_DIR@" taglib-1.9.1/doc/000077500000000000000000000000001222502465100135305ustar00rootroot00000000000000taglib-1.9.1/doc/README000066400000000000000000000001221222502465100144030ustar00rootroot00000000000000Run "make docs" in the parent directory to generate the TagLib API documentation. taglib-1.9.1/doc/api-footer.html000066400000000000000000000000521222502465100164600ustar00rootroot00000000000000 taglib-1.9.1/doc/api-header.html000066400000000000000000000026761222502465100164300ustar00rootroot00000000000000 $title ($projectname)
taglib-1.9.1/doc/taglib-api.css000066400000000000000000000132751222502465100162630ustar00rootroot00000000000000body { font-family: sans-serif; background: white; color: black; margin: 0px; padding: 15px; } a:link { font-weight: bold; text-decoration: none; color: gray; } a:visited { font-weight: bold; text-decoration: none; color: gray; } a:hover { color: #cccccc; text-decoration: underline; } a:active { color: #cccccc; text-decoration: underline; } img { border-style: none; } h1 { font-family: sans-serif; } h2 { font-family: sans-serif; } h3 { font-family: sans-serif; } /* container */ #container { position: absolute; border-width: thin; border-style: solid; width: 95%; } /* intro */ #intro { padding: 5px; margin: 0px; background: #cccccc; border-width: medium; border-style: solid; } #intro h1 { margin: 5px; padding: 5px; } /* links */ #links { font-size: x-small; vertical-align: bottom; } #links a { border-width: thin; border-style: dotted; border-color: white; /* margin: 0px 10px 0px 0px; */ margin: 1px; padding: 3px; line-height: 230% } #links a:hover { color: black; text-decoration: underline; } #links h3 { outline-width: thin; border-style: solid; padding: 2px; margin: 3px 0px 3px 0px; } /* menu */ #menu h3 { text-align: center; } /* text */ #text { margin: 0px; padding: 5px 5px 0px 5px; float: left; } #text h3 { border-width: thin; border-style: solid; padding: 2px; margin: 3px 0px 3px 0px; } #text li { margin: 0px 0px 10px 0px; } #text ul { margin: 5px; padding: 0px 0px 0px 20px; } #leftcolumn { float: left; width: 300px; margin: 0px 10px 0px 0px; padding: 0px; } #rightcolumn { float: right; width: 210px; margin: 0px; padding: 0px; } /* vspacer */ .vspacer { height: 10px; } .silver { border-width: thin; border-color: black; border-style: solid; background: #cccccc; } a.code { text-decoration: none; font-weight: normal; color: #4444ee } a.codeRef { font-weight: normal; color: #4444ee } div.fragment { width: 98%; border: 1px solid #CCCCCC; background-color: #f5f5f5; padding-left: 4px; margin: 4px; } div.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } #text td { width: auto; } div.memdoc { margin-top: 0px; margin-bottom: 20px; padding: 10px 10px 10px 40px; } div.memproto { border: thin solid black; background-color: #f2f2ff; width: 100%; margin-top: 20px; padding-top: 10px; padding-bottom: 10px; } td.paramtype { color: #602020; } table.memname { font-weight: bold; } div.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold } div.groupText { margin-left: 16px; font-style: italic; font-size: smaller } body { background: white; color: black; margin-right: 20px; margin-left: 20px; } td.indexkey { background-color: #eeeeff; font-weight: bold; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px } td.indexvalue { background-color: #eeeeff; font-style: italic; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px } tr.memlist { background-color: #f0f0f0; } p.formulaDsp { text-align: center; } img.formulaDsp { } img.formulaInl { vertical-align: middle; } span.keyword { color: #008000 } span.keywordtype { color: #604020 } span.keywordflow { color: #e08000 } span.comment { color: #800000 } span.preprocessor { color: #806020 } span.stringliteral { color: #002080 } span.charliteral { color: #008080 } .mdTable { border: 1px solid #868686; background-color: #f2f2ff; } .mdRow { padding: 8px 20px; } .mdescLeft { font-size: smaller; font-family: Arial, Helvetica, sans-serif; background-color: #FAFAFA; padding-left: 8px; border-top: 1px none #E0E0E0; border-right: 1px none #E0E0E0; border-bottom: 1px none #E0E0E0; border-left: 1px none #E0E0E0; margin: 0px; } .mdescRight { font-size: smaller; font-family: Arial, Helvetica, sans-serif; font-style: italic; background-color: #FAFAFA; padding-left: 4px; border-top: 1px none #E0E0E0; border-right: 1px none #E0E0E0; border-bottom: 1px none #E0E0E0; border-left: 1px none #E0E0E0; margin: 0px; padding-bottom: 0px; padding-right: 8px; } .memItemLeft { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-family: Geneva, Arial, Helvetica, sans-serif; font-size: 12px; } .memItemRight { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-family: Geneva, Arial, Helvetica, sans-serif; font-size: 13px; } .search { color: #0000ee; font-weight: bold; } form.search { margin-bottom: 0px; margin-top: 0px; } input.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #eeeeff; } td.tiny { font-size: 75%; } taglib-1.9.1/doc/taglib.png000066400000000000000000000052741222502465100155100ustar00rootroot00000000000000PNG  IHDR5sBITOtEXtSoftwareSodipodiPLTEotRNS  !"$%&'()*+,-./0123456789:;<=>@BCDEFGHIJKLMNOPQRSTUVXYZ[\^_`abcdefghijklmnoprvwxyz{|}~s IDATxWTeǿ ۀ0\w%6j.)5۵E$m4L+1ɅTnn`"*RY$n&j+]8xpxs?p/se^Q)A*lD{\,",",","," I|=ti遲Ł|{ 0=N@6l `2Hظe81hF'<zkŵJK (`uqJkYJ]K@99taiiֳa (!X|[ctr".cR`S$t,jKt;N$}RfRا,aܹڶA ؊@M- d' sTS,IIcEˠ4?$)v:H1^6-K^@p.ն,󬁯A">"k 49cK_m 8;VEs*DZ\Y),^ZD<`XWc^k <>0I|qy0( r^z@7}jWREO2=֤ }w>[-HHtA՞Z)wfIj8vģ[M mKHpo[o[`H۝z udž ^Ge' `1ZZ5AD_L޹HGYX9@L4dH$FHf>y>fϠ}zzr2h4@W!ib>Xv$t^"TtAq6DHEQn*Wf(.rQ&@R,UjeHWW!iU@C:N"*YEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXEXDb,ZiQ%*6(D`軉b3u !qzMX z"E]j@D%"Ih"Rzg+S" i#N=N]y~4 vu9Tb|)bRI /bpWg/9&s2QS=!±u/^DT<\gh}EHO}ENe<(*SR?+!> UCQ&E{ !B=5 HE‡Fx  f̌fc,W74R([Ȝˊj, SG|*ھ(er?G$EiZg yOEREoP4 @*J6JdߊdSz䙦]3nPTqGryzם7|Sd1wvBiOƾb^knkZ* Z8jΟJ͵VmIS稵햕]P0'T襈rE>EA!BPFDtM[At<5d[vzrhSB&`UDKO2)4!iN+"g7 GoEB/}Зk2MXEXEXE|$ҨJ㠪UA X+IENDB`taglib-1.9.1/examples/000077500000000000000000000000001222502465100146015ustar00rootroot00000000000000taglib-1.9.1/examples/CMakeLists.txt000066400000000000000000000021431222502465100173410ustar00rootroot00000000000000if(BUILD_EXAMPLES) INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../taglib ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/toolkit ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ape ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v1 ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2 ${CMAKE_CURRENT_SOURCE_DIR}/../bindings/c/ ) if(ENABLE_STATIC) add_definitions(-DTAGLIB_STATIC) endif(ENABLE_STATIC) ########### next target ############### ADD_EXECUTABLE(tagreader tagreader.cpp) TARGET_LINK_LIBRARIES(tagreader tag ) ########### next target ############### ADD_EXECUTABLE(tagreader_c tagreader_c.c) TARGET_LINK_LIBRARIES(tagreader_c tag_c ) ########### next target ############### ADD_EXECUTABLE(tagwriter tagwriter.cpp) TARGET_LINK_LIBRARIES(tagwriter tag ) ########### next target ############### ADD_EXECUTABLE(framelist framelist.cpp) TARGET_LINK_LIBRARIES(framelist tag ) ########### next target ############### ADD_EXECUTABLE(strip-id3v1 strip-id3v1.cpp) TARGET_LINK_LIBRARIES(strip-id3v1 tag ) endif(BUILD_EXAMPLES) taglib-1.9.1/examples/framelist.cpp000066400000000000000000000070611222502465100172770ustar00rootroot00000000000000/* Copyright (C) 2003 Scott Wheeler * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include #include #include #include #include #include #include #include #include using namespace std; using namespace TagLib; int main(int argc, char *argv[]) { // process the command line args for(int i = 1; i < argc; i++) { cout << "******************** \"" << argv[i] << "\"********************" << endl; MPEG::File f(argv[i]); ID3v2::Tag *id3v2tag = f.ID3v2Tag(); if(id3v2tag) { cout << "ID3v2." << id3v2tag->header()->majorVersion() << "." << id3v2tag->header()->revisionNumber() << ", " << id3v2tag->header()->tagSize() << " bytes in tag" << endl; ID3v2::FrameList::ConstIterator it = id3v2tag->frameList().begin(); for(; it != id3v2tag->frameList().end(); it++) cout << (*it)->frameID() << " - \"" << (*it)->toString() << "\"" << endl; } else cout << "file does not have a valid id3v2 tag" << endl; cout << endl << "ID3v1" << endl; ID3v1::Tag *id3v1tag = f.ID3v1Tag(); if(id3v1tag) { cout << "title - \"" << id3v1tag->title() << "\"" << endl; cout << "artist - \"" << id3v1tag->artist() << "\"" << endl; cout << "album - \"" << id3v1tag->album() << "\"" << endl; cout << "year - \"" << id3v1tag->year() << "\"" << endl; cout << "comment - \"" << id3v1tag->comment() << "\"" << endl; cout << "track - \"" << id3v1tag->track() << "\"" << endl; cout << "genre - \"" << id3v1tag->genre() << "\"" << endl; } else cout << "file does not have a valid id3v1 tag" << endl; APE::Tag *ape = f.APETag(); cout << endl << "APE" << endl; if(ape) { for(APE::ItemListMap::ConstIterator it = ape->itemListMap().begin(); it != ape->itemListMap().end(); ++it) { if((*it).second.type() != APE::Item::Binary) cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl; else cout << (*it).first << " - Binary data (" << (*it).second.binaryData().size() << " bytes)" << endl; } } else cout << "file does not have a valid APE tag" << endl; cout << endl; } } taglib-1.9.1/examples/strip-id3v1.cpp000066400000000000000000000031731222502465100173760ustar00rootroot00000000000000/* Copyright (C) 2003 Scott Wheeler * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include #include #include using namespace TagLib; int main(int argc, char *argv[]) { for(int i = 1; i < argc; i++) { std::cout << "******************** Stripping ID3v1 Tag From: \"" << argv[i] << "\"********************" << std::endl; MPEG::File f(argv[i]); f.strip(MPEG::File::ID3v1); } } taglib-1.9.1/examples/tagreader.cpp000066400000000000000000000067241222502465100172540ustar00rootroot00000000000000/* Copyright (C) 2003 Scott Wheeler * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include #include #include #include #include #include using namespace std; TagLib::String formatSeconds(int seconds) { char secondsString[3]; sprintf(secondsString, "%02i", seconds); return secondsString; } int main(int argc, char *argv[]) { for(int i = 1; i < argc; i++) { cout << "******************** \"" << argv[i] << "\" ********************" << endl; TagLib::FileRef f(argv[i]); if(!f.isNull() && f.tag()) { TagLib::Tag *tag = f.tag(); cout << "-- TAG (basic) --" << endl; cout << "title - \"" << tag->title() << "\"" << endl; cout << "artist - \"" << tag->artist() << "\"" << endl; cout << "album - \"" << tag->album() << "\"" << endl; cout << "year - \"" << tag->year() << "\"" << endl; cout << "comment - \"" << tag->comment() << "\"" << endl; cout << "track - \"" << tag->track() << "\"" << endl; cout << "genre - \"" << tag->genre() << "\"" << endl; TagLib::PropertyMap tags = f.file()->properties(); unsigned int longest = 0; for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) { if (i->first.size() > longest) { longest = i->first.size(); } } cout << "-- TAG (properties) --" << endl; for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) { for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) { cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl; } } } if(!f.isNull() && f.audioProperties()) { TagLib::AudioProperties *properties = f.audioProperties(); int seconds = properties->length() % 60; int minutes = (properties->length() - seconds) / 60; cout << "-- AUDIO --" << endl; cout << "bitrate - " << properties->bitrate() << endl; cout << "sample rate - " << properties->sampleRate() << endl; cout << "channels - " << properties->channels() << endl; cout << "length - " << minutes << ":" << formatSeconds(seconds) << endl; } } return 0; } taglib-1.9.1/examples/tagreader_c.c000066400000000000000000000055411222502465100172120ustar00rootroot00000000000000/* Copyright (C) 2003 Scott Wheeler * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include #include #ifndef FALSE #define FALSE 0 #endif int main(int argc, char *argv[]) { int i; int seconds; int minutes; TagLib_File *file; TagLib_Tag *tag; const TagLib_AudioProperties *properties; taglib_set_strings_unicode(FALSE); for(i = 1; i < argc; i++) { printf("******************** \"%s\" ********************\n", argv[i]); file = taglib_file_new(argv[i]); if(file == NULL) break; tag = taglib_file_tag(file); properties = taglib_file_audioproperties(file); if(tag != NULL) { printf("-- TAG --\n"); printf("title - \"%s\"\n", taglib_tag_title(tag)); printf("artist - \"%s\"\n", taglib_tag_artist(tag)); printf("album - \"%s\"\n", taglib_tag_album(tag)); printf("year - \"%i\"\n", taglib_tag_year(tag)); printf("comment - \"%s\"\n", taglib_tag_comment(tag)); printf("track - \"%i\"\n", taglib_tag_track(tag)); printf("genre - \"%s\"\n", taglib_tag_genre(tag)); } if(properties != NULL) { seconds = taglib_audioproperties_length(properties) % 60; minutes = (taglib_audioproperties_length(properties) - seconds) / 60; printf("-- AUDIO --\n"); printf("bitrate - %i\n", taglib_audioproperties_bitrate(properties)); printf("sample rate - %i\n", taglib_audioproperties_samplerate(properties)); printf("channels - %i\n", taglib_audioproperties_channels(properties)); printf("length - %i:%02i\n", minutes, seconds); } taglib_tag_free_strings(); taglib_file_free(file); } return 0; } taglib-1.9.1/examples/tagwriter.cpp000066400000000000000000000070451222502465100173230ustar00rootroot00000000000000/* Copyright (C) 2004 Scott Wheeler * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include #include #include #include #include #include #include #include #include #include using namespace std; bool isArgument(const char *s) { return strlen(s) == 2 && s[0] == '-'; } bool isFile(const char *s) { struct stat st; #ifdef _WIN32 return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG)); #else return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG | S_IFLNK)); #endif } void usage() { cout << endl; cout << "Usage: tagwriter " << endl; cout << endl; cout << "Where the valid fields are:" << endl; cout << " -t " << endl; cout << " -a <artist>" << endl; cout << " -A <album>" << endl; cout << " -c <comment>" << endl; cout << " -g <genre>" << endl; cout << " -y <year>" << endl; cout << " -T <track>" << endl; cout << endl; exit(1); } int main(int argc, char *argv[]) { TagLib::List<TagLib::FileRef> fileList; while(argc > 0 && isFile(argv[argc - 1])) { TagLib::FileRef f(argv[argc - 1]); if(!f.isNull() && f.tag()) fileList.append(f); argc--; } if(fileList.isEmpty()) usage(); for(int i = 1; i < argc - 1; i += 2) { if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) { char field = argv[i][1]; TagLib::String value = argv[i + 1]; TagLib::List<TagLib::FileRef>::Iterator it; for(it = fileList.begin(); it != fileList.end(); ++it) { TagLib::Tag *t = (*it).tag(); switch (field) { case 't': t->setTitle(value); break; case 'a': t->setArtist(value); break; case 'A': t->setAlbum(value); break; case 'c': t->setComment(value); break; case 'g': t->setGenre(value); break; case 'y': t->setYear(value.toInt()); break; case 'T': t->setTrack(value.toInt()); break; default: usage(); break; } } } else usage(); } TagLib::List<TagLib::FileRef>::Iterator it; for(it = fileList.begin(); it != fileList.end(); ++it) (*it).file()->save(); return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib-config.cmake��������������������������������������������������������������������0000664�0000000�0000000�00000001326�12225024651�0016474�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh usage() { echo "usage: $0 [OPTIONS]" cat << EOH options: [--libs] [--cflags] [--version] [--prefix] EOH exit 1; } prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${LIB_INSTALL_DIR} includedir=${INCLUDE_INSTALL_DIR} 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 ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION} ;; --prefix) echo $prefix ;; *) echo "$0: unknown option $1" echo usage ;; esac shift done if test -n "$flags" then echo $flags fi ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib-config.cmd.cmake����������������������������������������������������������������0000664�0000000�0000000�00000002172�12225024651�0017236�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@echo off goto beginning * * It is what it is, you can do with it as you please. * * Just don't blame me if it teaches your computer to smoke! * * -Enjoy * fh :)_~ * :beginning if /i "%1#" == "--libs#" goto doit if /i "%1#" == "--cflags#" goto doit if /i "%1#" == "--version#" goto doit if /i "%1#" == "--prefix#" goto doit echo "usage: %0 [OPTIONS]" echo [--libs] echo [--cflags] echo [--version] echo [--prefix] goto theend * * NOTE: Windows does not assume libraries are prefixed with 'lib'. * NOTE: If '-llibtag' is the last element, it is easily appended in the users installation/makefile process * to allow for static, shared or debug builds. * It would be preferable if the top level CMakeLists.txt provided the library name during config. ?? :doit if /i "%1#" == "--libs#" echo -L${LIB_INSTALL_DIR} -llibtag if /i "%1#" == "--cflags#" echo -I${INCLUDE_INSTALL_DIR}/taglib if /i "%1#" == "--version#" echo ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION} if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX} :theend ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib.pc.cmake������������������������������������������������������������������������0000664�0000000�0000000�00000000544�12225024651�0015633�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������prefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${LIB_INSTALL_DIR} includedir=${INCLUDE_INSTALL_DIR} Name: TagLib Description: Audio meta-data library Requires: Version: ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION} Libs: -L${LIB_INSTALL_DIR} -ltag Cflags: -I${INCLUDE_INSTALL_DIR}/taglib ������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/��������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014225�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/CMakeLists.txt������������������������������������������������������������������0000664�0000000�0000000�00000016460�12225024651�0016774�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������set(CMAKE_INCLUDE_CURRENT_DIR ON) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/toolkit ${CMAKE_CURRENT_SOURCE_DIR}/asf ${CMAKE_CURRENT_SOURCE_DIR}/mpeg ${CMAKE_CURRENT_SOURCE_DIR}/ogg ${CMAKE_CURRENT_SOURCE_DIR}/ogg/flac ${CMAKE_CURRENT_SOURCE_DIR}/flac ${CMAKE_CURRENT_SOURCE_DIR}/mpc ${CMAKE_CURRENT_SOURCE_DIR}/mp4 ${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis ${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex ${CMAKE_CURRENT_SOURCE_DIR}/ogg/opus ${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2 ${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2/frames ${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v1 ${CMAKE_CURRENT_SOURCE_DIR}/ape ${CMAKE_CURRENT_SOURCE_DIR}/wavpack ${CMAKE_CURRENT_SOURCE_DIR}/trueaudio ${CMAKE_CURRENT_SOURCE_DIR}/riff ${CMAKE_CURRENT_SOURCE_DIR}/riff/aiff ${CMAKE_CURRENT_SOURCE_DIR}/riff/wav ${CMAKE_CURRENT_SOURCE_DIR}/mod ${CMAKE_CURRENT_SOURCE_DIR}/s3m ${CMAKE_CURRENT_SOURCE_DIR}/it ${CMAKE_CURRENT_SOURCE_DIR}/xm ) if(ZLIB_FOUND) include_directories(${ZLIB_INCLUDE_DIR}) endif() set(tag_HDRS tag.h fileref.h audioproperties.h taglib_export.h ${CMAKE_BINARY_DIR}/taglib_config.h toolkit/taglib.h toolkit/tstring.h toolkit/tlist.h toolkit/tlist.tcc toolkit/tstringlist.h toolkit/tbytevector.h toolkit/tbytevectorlist.h toolkit/tbytevectorstream.h toolkit/tiostream.h toolkit/tfile.h toolkit/tfilestream.h toolkit/tmap.h toolkit/tmap.tcc toolkit/tpropertymap.h toolkit/trefcounter.h toolkit/tdebuglistener.h mpeg/mpegfile.h mpeg/mpegproperties.h mpeg/mpegheader.h mpeg/xingheader.h mpeg/id3v1/id3v1tag.h mpeg/id3v1/id3v1genres.h mpeg/id3v2/id3v2extendedheader.h mpeg/id3v2/id3v2frame.h mpeg/id3v2/id3v2header.h mpeg/id3v2/id3v2synchdata.h mpeg/id3v2/id3v2footer.h mpeg/id3v2/id3v2framefactory.h mpeg/id3v2/id3v2tag.h mpeg/id3v2/frames/attachedpictureframe.h mpeg/id3v2/frames/commentsframe.h mpeg/id3v2/frames/generalencapsulatedobjectframe.h mpeg/id3v2/frames/ownershipframe.h mpeg/id3v2/frames/popularimeterframe.h mpeg/id3v2/frames/privateframe.h mpeg/id3v2/frames/relativevolumeframe.h mpeg/id3v2/frames/textidentificationframe.h mpeg/id3v2/frames/uniquefileidentifierframe.h mpeg/id3v2/frames/unknownframe.h mpeg/id3v2/frames/unsynchronizedlyricsframe.h mpeg/id3v2/frames/urllinkframe.h ogg/oggfile.h ogg/oggpage.h ogg/oggpageheader.h ogg/xiphcomment.h ogg/vorbis/vorbisfile.h ogg/vorbis/vorbisproperties.h ogg/flac/oggflacfile.h ogg/speex/speexfile.h ogg/speex/speexproperties.h ogg/opus/opusfile.h ogg/opus/opusproperties.h flac/flacfile.h flac/flacpicture.h flac/flacproperties.h flac/flacmetadatablock.h ape/apefile.h ape/apeproperties.h ape/apetag.h ape/apefooter.h ape/apeitem.h mpc/mpcfile.h mpc/mpcproperties.h wavpack/wavpackfile.h wavpack/wavpackproperties.h trueaudio/trueaudiofile.h trueaudio/trueaudioproperties.h riff/rifffile.h riff/aiff/aifffile.h riff/aiff/aiffproperties.h riff/wav/wavfile.h riff/wav/wavproperties.h riff/wav/infotag.h asf/asffile.h asf/asfproperties.h asf/asftag.h asf/asfattribute.h asf/asfpicture.h mp4/mp4file.h mp4/mp4atom.h mp4/mp4tag.h mp4/mp4item.h mp4/mp4properties.h mp4/mp4coverart.h mod/modfilebase.h mod/modfile.h mod/modtag.h mod/modproperties.h it/itfile.h it/itproperties.h s3m/s3mfile.h s3m/s3mproperties.h xm/xmfile.h xm/xmproperties.h ) set(mpeg_SRCS mpeg/mpegfile.cpp mpeg/mpegproperties.cpp mpeg/mpegheader.cpp mpeg/xingheader.cpp ) set(id3v1_SRCS mpeg/id3v1/id3v1tag.cpp mpeg/id3v1/id3v1genres.cpp ) set(id3v2_SRCS mpeg/id3v2/id3v2framefactory.cpp mpeg/id3v2/id3v2synchdata.cpp mpeg/id3v2/id3v2tag.cpp mpeg/id3v2/id3v2header.cpp mpeg/id3v2/id3v2frame.cpp mpeg/id3v2/id3v2footer.cpp mpeg/id3v2/id3v2extendedheader.cpp ) set(frames_SRCS mpeg/id3v2/frames/attachedpictureframe.cpp mpeg/id3v2/frames/commentsframe.cpp mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp mpeg/id3v2/frames/ownershipframe.cpp mpeg/id3v2/frames/popularimeterframe.cpp mpeg/id3v2/frames/privateframe.cpp mpeg/id3v2/frames/relativevolumeframe.cpp mpeg/id3v2/frames/textidentificationframe.cpp mpeg/id3v2/frames/uniquefileidentifierframe.cpp mpeg/id3v2/frames/unknownframe.cpp mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp mpeg/id3v2/frames/urllinkframe.cpp ) set(ogg_SRCS ogg/oggfile.cpp ogg/oggpage.cpp ogg/oggpageheader.cpp ogg/xiphcomment.cpp ) set(vorbis_SRCS ogg/vorbis/vorbisfile.cpp ogg/vorbis/vorbisproperties.cpp ) set(flacs_SRCS flac/flacfile.cpp flac/flacpicture.cpp flac/flacproperties.cpp flac/flacmetadatablock.cpp flac/flacunknownmetadatablock.cpp ) set(oggflacs_SRCS ogg/flac/oggflacfile.cpp ) set(mpc_SRCS mpc/mpcfile.cpp mpc/mpcproperties.cpp ) set(mp4_SRCS mp4/mp4file.cpp mp4/mp4atom.cpp mp4/mp4tag.cpp mp4/mp4item.cpp mp4/mp4properties.cpp mp4/mp4coverart.cpp ) set(ape_SRCS ape/apetag.cpp ape/apefooter.cpp ape/apeitem.cpp ape/apefile.cpp ape/apeproperties.cpp ) set(wavpack_SRCS wavpack/wavpackfile.cpp wavpack/wavpackproperties.cpp ) set(speex_SRCS ogg/speex/speexfile.cpp ogg/speex/speexproperties.cpp ) set(opus_SRCS ogg/opus/opusfile.cpp ogg/opus/opusproperties.cpp ) set(trueaudio_SRCS trueaudio/trueaudiofile.cpp trueaudio/trueaudioproperties.cpp ) set(asf_SRCS asf/asftag.cpp asf/asffile.cpp asf/asfproperties.cpp asf/asfattribute.cpp asf/asfpicture.cpp ) set(riff_SRCS riff/rifffile.cpp ) set(aiff_SRCS riff/aiff/aifffile.cpp riff/aiff/aiffproperties.cpp ) set(wav_SRCS riff/wav/wavfile.cpp riff/wav/wavproperties.cpp riff/wav/infotag.cpp ) set(mod_SRCS mod/modfilebase.cpp mod/modfile.cpp mod/modtag.cpp mod/modproperties.cpp ) set(s3m_SRCS s3m/s3mfile.cpp s3m/s3mproperties.cpp ) set(it_SRCS it/itfile.cpp it/itproperties.cpp ) set(xm_SRCS xm/xmfile.cpp xm/xmproperties.cpp ) set(toolkit_SRCS toolkit/tstring.cpp toolkit/tstringlist.cpp toolkit/tbytevector.cpp toolkit/tbytevectorlist.cpp toolkit/tbytevectorstream.cpp toolkit/tiostream.cpp toolkit/tfile.cpp toolkit/tfilestream.cpp toolkit/tdebug.cpp toolkit/tpropertymap.cpp toolkit/trefcounter.cpp toolkit/tdebuglistener.cpp toolkit/unicode.cpp ) set(tag_LIB_SRCS ${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS} ${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS} ${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS} ${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS} tag.cpp tagunion.cpp fileref.cpp audioproperties.cpp ) add_library(tag ${tag_LIB_SRCS} ${tag_HDRS}) if(ZLIB_FOUND) target_link_libraries(tag ${ZLIB_LIBRARIES}) endif() set_target_properties(tag PROPERTIES VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} SOVERSION ${TAGLIB_SOVERSION_MAJOR} INSTALL_NAME_DIR ${LIB_INSTALL_DIR} DEFINE_SYMBOL MAKE_TAGLIB_LIB LINK_INTERFACE_LIBRARIES "" PUBLIC_HEADER "${tag_HDRS}" ) if(BUILD_FRAMEWORK) set_target_properties(tag PROPERTIES FRAMEWORK TRUE) endif() install(TARGETS tag FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION ${BIN_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014772�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/ape-tag-format.txt����������������������������������������������������������0000664�0000000�0000000�00000020114�12225024651�0020335�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������================================================================================ = APE Tag Specification, Version 2.000 ================================================================================ Original Content (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de> Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org> ================================================================================ = Contents ================================================================================ 1 - APE Tag General Structure 2 - APE Tag Header / Footer Format 3 - APE Tag Flags 4 - APE Tag Item Format 5 - APE Tag Item Supported Keys 6 - APE Tag Item Content 7 - Data Types 7.1 - Data Types / UTF-8 7.2 - Data Types / Dates 7.3 - Data Types / Timestamps ================================================================================ = 1 - APE Tag General Structure ================================================================================ Member of Basic Components of SV8 Stream Note: It is strongly recommended that the data size be stored in the tags. The size should normally be in the roughly one kilobyte, never more than 8 kilobytes. Larger data should be stored externally using link entries. Linked data is much easier to process by normal programs, so for instance JPEG data should not be included inside the audio file. APE Tag Version 2.000 (with header, recommended): /================================\ | APE Tag Header | 32 bytes | |-------------------|------------| | APE Tag Item 1 | > 10 bytes | | APE Tag Item 2 | > 10 bytes | | APE Tag Item n-1 | > 10 bytes | | APE Tag Item n | > 10 bytes | |-------------------|------------| | APE Tag Footer | 32 bytes | \================================/ APE tag items should be sorted ascending by size. When streaming, parts of the APE tag may be dropped to reduce the danger of drop outs between tracks. This is not required, but is strongly recommended. It would be desirable for the i tems to be sorted by importance / size, but this is not feasible. This convention should only be broken when adding less important small items and it is not desirable to rewrite the entire tag. An APE tag at the end of a file (the recommended location) must have at least a footer; an APE tag at the beginning of a file (strongly discouraged) must have at least a header. APE Tag Version 1.000 (without header, deprecated) /================================\ | APE Tag Item 1 | > 10 bytes | | APE Tag Item 2 | > 10 bytes | | APE Tag Item n-1 | > 10 bytes | | APE Tag Item n | > 10 bytes | |-------------------|------------| | APE Tag Footer | 32 bytes | \================================/ ================================================================================ = 2 - APE Tag Header / Footer Format ================================================================================ Contains number, length and attributes of all tag items Header and Footer are different in 1 bit in the Tags Flags to distinguish between them. Member of APE Tag 2.0 /===========================================================================\ | Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } | |----------------|---------|------------------------------------------------| | Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 | |----------------|---------|------------------------------------------------| | Tag Size | 4 bytes | Tag size in bytes including footer and all tag | | | | items excluding the header (for 1.000 | | | | compatibility) | |----------------|---------|------------------------------------------------| | Item Count | 4 bytes | Number of items in the tag | |----------------|---------|------------------------------------------------| | Tag Flags | 4 bytes | Global flags | |----------------|---------|------------------------------------------------| | Reserved | 8 bytes | Must be zeroed | \===========================================================================/ ================================================================================ = 3 - APE Tag Flags ================================================================================ The general flag structure for either items or headers / footers is the same. Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are item specific. Note: APE Tags from Version 1.0 do not use any of the following. All flags in that version are zeroed and ignored when reading. /=================================================================\ | Contains Header | Bit 31 | 1 - has header | 0 - no header | |-----------------|-------------|---------------------------------| | Contains Footer | Bit 30 | 1 - has footer | 0 - no footer | |-----------------|-------------|---------------------------------| | Is Header | Bit 29 | 1 - is header | 0 - is footer | |-----------------|-------------|---------------------------------| | Undefined | Bits 28 - 3 | Undefined, must be zeroed | |-----------------|-------------|---------------------------------| | Encoding | Bits 2 - 1 | 00 - UTF-8 | | | | 01 - Binary Data * | | | | 10 - External Reference ** | | | | 11 - Reserved | |-----------------|-------------|---------------------------------| | Read Only | Bit 0 | 1 - read only | 0 - read/write | \=================================================================/ (*) Should be ignored by tools for editing text values (**) Allowed external reference formats: - http://host/directory/filename.ext - ftp://host/directory/filename.ext - filename.ext - /directory/filename.ext - DRIVE:/directory/filename.ext Note: External references are also UTF-8 encoded. ================================================================================ = 4 - APE Tag Item Format ================================================================================ APE Tag Items are stored as key-value pairs. APE Tags Item Key are case sensitive, however it is illegal to use keys which only differ in case and it is recommended that tag reading not be case sensitive. Every key can only occur (at most) once. It is not possible to repeat a key to signify updated contents. Tags can be partially or completely repeated in the streaming format. This makes it possible to display an artist and / or title if it was missed at the beginning of the stream. It is recommended that the important information like artist, album and title should occur approximately every 2 minutes in the stream and again 5 to 10 seconds before the end. However, care should be tak en not to replicate this information too often or during passages with high bitrate demands to avoid unnecessary drop-outs. /==============================================================================\ | Content Size | 4 bytes | Length of the value in bytes | |----------------|---------------|---------------------------------------------| | Flags | 4 bytes | Item flags | |----------------|---------------|---------------------------------------------| | Key | 2 - 255 bytes | Item key | |----------------|---------------|---------------------------------------------| | Key Terminator | 1 byte | Null byte that indicates the end of the key | |----------------|---------------|---------------------------------------------| | Value | variable | Content (formatted according to the flags) | \==============================================================================/ ================================================================================ Sections 5 - 7 haven't yet been converted from: http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apefile.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000017157�12225024651�0017116�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2010 by Alex Novichkov email : novichko@atnet.ru copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com (original WavPack implementation) copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tstring.h> #include <tdebug.h> #include <tagunion.h> #include <id3v1tag.h> #include <tpropertymap.h> #include "apefile.h" #include "apetag.h" #include "apefooter.h" using namespace TagLib; namespace { enum { ApeAPEIndex = 0, ApeID3v1Index = 1 }; } class APE::File::FilePrivate { public: FilePrivate() : APELocation(-1), APESize(0), ID3v1Location(-1), properties(0), hasAPE(false), hasID3v1(false) {} ~FilePrivate() { delete properties; } long APELocation; uint APESize; long ID3v1Location; TagUnion tag; Properties *properties; // 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; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// APE::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } APE::File::~File() { delete d; } TagLib::Tag *APE::File::tag() const { return &d->tag; } PropertyMap APE::File::properties() const { if(d->hasAPE) return d->tag.access<APE::Tag>(ApeAPEIndex, false)->properties(); if(d->hasID3v1) return d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->properties(); return PropertyMap(); } void APE::File::removeUnsupportedProperties(const StringList &properties) { if(d->hasAPE) d->tag.access<APE::Tag>(ApeAPEIndex, false)->removeUnsupportedProperties(properties); if(d->hasID3v1) d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->removeUnsupportedProperties(properties); } PropertyMap APE::File::setProperties(const PropertyMap &properties) { if(d->hasID3v1) d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->setProperties(properties); return d->tag.access<APE::Tag>(ApeAPEIndex, true)->setProperties(properties); } APE::Properties *APE::File::audioProperties() const { return d->properties; } bool APE::File::save() { if(readOnly()) { debug("APE::File::save() -- File is read only."); return false; } // Update ID3v1 tag if(ID3v1Tag()) { if(d->hasID3v1) { seek(d->ID3v1Location); writeBlock(ID3v1Tag()->render()); } else { seek(0, End); d->ID3v1Location = tell(); writeBlock(ID3v1Tag()->render()); d->hasID3v1 = true; } } else { if(d->hasID3v1) { removeBlock(d->ID3v1Location, 128); d->hasID3v1 = false; if(d->hasAPE) { if(d->APELocation > d->ID3v1Location) d->APELocation -= 128; } } } // Update APE tag if(APETag()) { if(d->hasAPE) insert(APETag()->render(), d->APELocation, d->APESize); else { if(d->hasID3v1) { insert(APETag()->render(), d->ID3v1Location, 0); d->APESize = APETag()->footer()->completeTagSize(); d->hasAPE = true; d->APELocation = d->ID3v1Location; d->ID3v1Location += d->APESize; } else { seek(0, End); d->APELocation = tell(); writeBlock(APETag()->render()); d->APESize = APETag()->footer()->completeTagSize(); d->hasAPE = true; } } } else { if(d->hasAPE) { removeBlock(d->APELocation, d->APESize); d->hasAPE = false; if(d->hasID3v1) { if(d->ID3v1Location > d->APELocation) { d->ID3v1Location -= d->APESize; } } } } return true; } ID3v1::Tag *APE::File::ID3v1Tag(bool create) { return d->tag.access<ID3v1::Tag>(ApeID3v1Index, create); } APE::Tag *APE::File::APETag(bool create) { return d->tag.access<APE::Tag>(ApeAPEIndex, create); } void APE::File::strip(int tags) { if(tags & ID3v1) { d->tag.set(ApeID3v1Index, 0); APETag(true); } if(tags & APE) { d->tag.set(ApeAPEIndex, 0); if(!ID3v1Tag()) APETag(true); } } bool APE::File::hasAPETag() const { return d->hasAPE; } bool APE::File::hasID3v1Tag() const { return d->hasID3v1; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) { // Look for an ID3v1 tag d->ID3v1Location = findID3v1(); if(d->ID3v1Location >= 0) { d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); d->hasID3v1 = true; } // Look for an APE tag d->APELocation = findAPE(); if(d->APELocation >= 0) { d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation)); d->APESize = APETag()->footer()->completeTagSize(); d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; d->hasAPE = true; } if(!d->hasID3v1) APETag(true); // Look for APE audio properties if(readProperties) { d->properties = new Properties(this); } } long APE::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 APE::File::findID3v1() { if(!isValid()) return -1; seek(-128, End); long p = tell(); if(readBlock(3) == ID3v1::Tag::fileIdentifier()) return p; return -1; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apefile.h�������������������������������������������������������������������0000664�0000000�0000000�00000020036�12225024651�0016551�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2010 by Alex Novichkov email : novichko@atnet.ru copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com (original WavPack implementation) copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_APEFILE_H #define TAGLIB_APEFILE_H #include "tfile.h" #include "taglib_export.h" #include "apeproperties.h" namespace TagLib { class Tag; namespace ID3v1 { class Tag; } namespace APE { class Tag; } //! An implementation of APE metadata /*! * This is implementation of APE metadata. * * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream * properties from the file. */ namespace APE { //! An implementation of TagLib::File with APE specific methods /*! * This implements and provides an interface for APE 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 APE files. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * This set of flags is used for various operations and is suitable for * being OR-ed together. */ enum TagTypes { //! Empty set. Matches no tag types. NoTags = 0x0000, //! Matches ID3v1 tags. ID3v1 = 0x0001, //! Matches APE tags. APE = 0x0002, //! Matches all tag types. AllTags = 0xffff }; /*! * Constructs an APE file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an APE file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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; /*! * Implements the unified property interface -- export function. * If the file contains both an APE and an ID3v1 tag, only APE * will be converted to the PropertyMap. */ PropertyMap properties() const; /*! * Removes unsupported properties. Forwards to the actual Tag's * removeUnsupportedProperties() function. */ void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. * Creates an APEv2 tag if necessary. A pontentially existing ID3v1 * tag will be updated as well. */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the APE::Properties for this file. If no audio properties * were read then this will return a null pointer. */ virtual Properties *audioProperties() const; /*! * Saves the file. * * \note According to the official Monkey's Audio SDK, an APE file * can only have either ID3V1 or APE tags, so a parameter is used here. */ virtual bool save(); /*! * Returns a pointer to the ID3v1 tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file * on disk actually has an ID3v1 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v1Tag() */ ID3v1::Tag *ID3v1Tag(bool create = false); /*! * Returns a pointer to the APE tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an APE tag. Use hasAPETag() to check if the file * on disk actually has an APE tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasAPETag() */ 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 strip(int tags = AllTags); /*! * Returns whether or not the file on disk actually has an APE tag. * * \see APETag() */ bool hasAPETag() const; /*! * Returns whether or not the file on disk actually has an ID3v1 tag. * * \see ID3v1Tag() */ bool hasID3v1Tag() const; private: File(const File &); File &operator=(const File &); void read(bool readProperties, Properties::ReadStyle propertiesStyle); void scan(); long findID3v1(); long findAPE(); class FilePrivate; FilePrivate *d; }; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apefooter.cpp���������������������������������������������������������������0000664�0000000�0000000�00000013004�12225024651�0017460�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2004 by Allan Sandfeld Jensen (C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp) email : kde@carewolf.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <iostream> #include <bitset> #include <tstring.h> #include <tdebug.h> #include "apefooter.h" using namespace TagLib; using namespace APE; class APE::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 APE::Footer::size() { return FooterPrivate::size; } ByteVector APE::Footer::fileIdentifier() { return ByteVector::fromCString("APETAGEX"); } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// APE::Footer::Footer() { d = new FooterPrivate; } APE::Footer::Footer(const ByteVector &data) { d = new FooterPrivate; parse(data); } APE::Footer::~Footer() { delete d; } TagLib::uint APE::Footer::version() const { return d->version; } bool APE::Footer::headerPresent() const { return d->headerPresent; } bool APE::Footer::footerPresent() const { return d->footerPresent; } bool APE::Footer::isHeader() const { return d->isHeader; } void APE::Footer::setHeaderPresent(bool b) const { d->headerPresent = b; } TagLib::uint APE::Footer::itemCount() const { return d->itemCount; } void APE::Footer::setItemCount(uint s) { d->itemCount = s; } TagLib::uint APE::Footer::tagSize() const { return d->tagSize; } TagLib::uint APE::Footer::completeTagSize() const { if(d->headerPresent) return d->tagSize + d->size; else return d->tagSize; } void APE::Footer::setTagSize(uint s) { d->tagSize = s; } void APE::Footer::setData(const ByteVector &data) { parse(data); } ByteVector APE::Footer::renderFooter() const { return render(false); } ByteVector APE::Footer::renderHeader() const { if (!d->headerPresent) return ByteVector(); return render(true); } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void APE::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.toUInt(8, false); // Read the tag size d->tagSize = data.toUInt(12, false); // Read the item count d->itemCount = data.toUInt(16, false); // Read the flags std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false))); d->headerPresent = flags[31]; d->footerPresent = !flags[30]; d->isHeader = flags[29]; } ByteVector APE::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; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apefooter.h�����������������������������������������������������������������0000664�0000000�0000000�00000012040�12225024651�0017124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_APEFOOTER_H #define TAGLIB_APEFOOTER_H #include "tbytevector.h" #include "taglib_export.h" namespace TagLib { namespace APE { //! An implementation of APE footers /*! * This class implements APE footers (and headers). It attempts to follow, both * semantically and programatically, the structure specified in * the APE v2.0 standard. The API is based on the properties of APE footer and * headers specified there. */ class TAGLIB_EXPORT Footer { public: /*! * Constructs an empty APE footer. */ Footer(); /*! * Constructs an APE footer based on \a data. parse() is called * immediately. */ Footer(const ByteVector &data); /*! * Destroys the footer. */ virtual ~Footer(); /*! * Returns the version number. (Note: This is the 1000 or 2000.) */ uint version() const; /*! * Returns true if a header is present in the tag. */ bool headerPresent() const; /*! * Returns true if a footer is present in the tag. */ bool footerPresent() const; /*! * Returns true this is actually the header. */ bool isHeader() const; /*! * Sets whether the header should be rendered or not */ void setHeaderPresent(bool b) const; /*! * Returns the number of items in the tag. */ uint itemCount() const; /*! * Set the item count to \a s. * \see itemCount() */ void setItemCount(uint s); /*! * Returns the tag size in bytes. This is the size of the frame content and footer. * The size of the \e entire tag will be this plus the header size, if present. * * \see completeTagSize() */ uint tagSize() const; /*! * Returns the tag size, including if present, the header * size. * * \see tagSize() */ uint completeTagSize() const; /*! * Set the tag size to \a s. * \see tagSize() */ void setTagSize(uint s); /*! * Returns the size of the footer. Presently this is always 32 bytes. */ static uint size(); /*! * Returns the string used to identify an APE tag inside of a file. * Presently this is always "APETAGEX". */ static ByteVector fileIdentifier(); /*! * Sets the data that will be used as the footer. 32 bytes, * starting from \a data will be used. */ void setData(const ByteVector &data); /*! * Renders the footer back to binary format. */ ByteVector renderFooter() const; /*! * Renders the header corresponding to the footer. If headerPresent is * set to false, it returns an empty ByteVector. */ ByteVector renderHeader() const; protected: /*! * Called by setData() to parse the footer data. It makes this information * available through the public API. */ void parse(const ByteVector &data); /*! * Called by renderFooter and renderHeader */ ByteVector render(bool isHeader) const; private: Footer(const Footer &); Footer &operator=(const Footer &); class FooterPrivate; FooterPrivate *d; }; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apeitem.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000014510�12225024651�0017123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevectorlist.h> #include <tdebug.h> #include "apeitem.h" using namespace TagLib; using namespace APE; class APE::Item::ItemPrivate { public: ItemPrivate() : type(Text), readOnly(false) {} Item::ItemTypes type; String key; ByteVector value; StringList text; bool readOnly; }; APE::Item::Item() { d = new ItemPrivate; } APE::Item::Item(const String &key, const String &value) { d = new ItemPrivate; d->key = key; d->text.append(value); } APE::Item::Item(const String &key, const StringList &values) { d = new ItemPrivate; d->key = key; d->text = values; } APE::Item::Item(const String &key, const ByteVector &value, bool binary) { d = new ItemPrivate; d->key = key; if(binary) { d->type = Binary; d->value = value; } else d->text.append(value); } APE::Item::Item(const Item &item) { d = new ItemPrivate(*item.d); } APE::Item::~Item() { delete d; } Item &APE::Item::operator=(const Item &item) { delete d; d = new ItemPrivate(*item.d); return *this; } void APE::Item::setReadOnly(bool readOnly) { d->readOnly = readOnly; } bool APE::Item::isReadOnly() const { return d->readOnly; } void APE::Item::setType(APE::Item::ItemTypes val) { d->type = val; } APE::Item::ItemTypes APE::Item::type() const { return d->type; } String APE::Item::key() const { return d->key; } ByteVector APE::Item::binaryData() const { return d->value; } void APE::Item::setBinaryData(const ByteVector &value) { d->type = Binary; d->value = value; d->text.clear(); } ByteVector APE::Item::value() const { // This seems incorrect as it won't be actually rendering the value to keep it // up to date. return d->value; } void APE::Item::setKey(const String &key) { d->key = key; } void APE::Item::setValue(const String &value) { d->type = Text; d->text = value; d->value.clear(); } void APE::Item::setValues(const StringList &value) { d->type = Text; d->text = value; d->value.clear(); } void APE::Item::appendValue(const String &value) { d->type = Text; d->text.append(value); d->value.clear(); } void APE::Item::appendValues(const StringList &values) { d->type = Text; d->text.append(values); d->value.clear(); } int APE::Item::size() const { // SFB: Why is d->key.size() used when size() returns the length in UniChars and not UTF-8? int result = 8 + d->key.size() /* d->key.data(String::UTF8).size() */ + 1; switch (d->type) { case Text: if(d->text.size()) { StringList::ConstIterator it = d->text.begin(); result += it->data(String::UTF8).size(); it++; for(; it != d->text.end(); ++it) result += 1 + it->data(String::UTF8).size(); } break; case Binary: case Locator: result += d->value.size(); break; } return result; } StringList APE::Item::toStringList() const { return d->text; } StringList APE::Item::values() const { return d->text; } String APE::Item::toString() const { if(d->type == Text && !isEmpty()) return d->text.front(); else return String::null; } bool APE::Item::isEmpty() const { switch(d->type) { case Text: if(d->text.isEmpty()) return true; if(d->text.size() == 1 && d->text.front().isEmpty()) return true; return false; case Binary: case Locator: return d->value.isEmpty(); default: return false; } } void APE::Item::parse(const ByteVector &data) { // 11 bytes is the minimum size for an APE item if(data.size() < 11) { debug("APE::Item::parse() -- no data in item"); return; } const uint valueLength = data.toUInt(0, false); const uint flags = data.toUInt(4, false); d->key = String(data.mid(8), String::UTF8); const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength); setReadOnly(flags & 1); setType(ItemTypes((flags >> 1) & 3)); if(Text == d->type) d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8); else d->value = value; } ByteVector APE::Item::render() const { ByteVector data; TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); ByteVector value; if(isEmpty()) return data; if(d->type == Text) { StringList::ConstIterator it = d->text.begin(); value.append(it->data(String::UTF8)); it++; for(; it != d->text.end(); ++it) { value.append('\0'); value.append(it->data(String::UTF8)); } d->value = value; } else value.append(d->value); data.append(ByteVector::fromUInt(value.size(), false)); data.append(ByteVector::fromUInt(flags, false)); data.append(d->key.data(String::UTF8)); data.append(ByteVector('\0')); data.append(value); return data; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apeitem.h�������������������������������������������������������������������0000664�0000000�0000000�00000014106�12225024651�0016571�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_APEITEM_H #define TAGLIB_APEITEM_H #include "tbytevector.h" #include "tstring.h" #include "tstringlist.h" namespace TagLib { namespace APE { //! An implementation of APE-items /*! * This class provides the features of items in the APEv2 standard. */ class TAGLIB_EXPORT Item { public: /*! * Enum of types an Item can have. The value of 3 is reserved. */ enum ItemTypes { //! Item contains text information coded in UTF-8 Text = 0, //! Item contains binary information Binary = 1, //! Item is a locator of external stored information Locator = 2 }; /*! * Constructs an empty item. */ Item(); /*! * Constructs a text item with \a key and \a value. */ // BIC: Remove this, StringList has a constructor from a single string Item(const String &key, const String &value); /*! * Constructs a text item with \a key and \a values. */ Item(const String &key, const StringList &values); /*! * Constructs an item with \a key and \a value. * If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text */ Item(const String &key, const ByteVector &value, bool binary); /*! * Construct an item as a copy of \a item. */ Item(const Item &item); /*! * Destroys the item. */ virtual ~Item(); /*! * Copies the contents of \a item into this item. */ Item &operator=(const Item &item); /*! * Returns the key. */ String key() const; /*! * Returns the binary value. * If the item type is not \a Binary, always returns an empty ByteVector. */ ByteVector binaryData() const; /*! * Set the binary value to \a value * The item's type will also be set to \a Binary */ void setBinaryData(const ByteVector &value); #ifndef DO_NOT_DOCUMENT /* Remove in next binary incompatible release */ ByteVector value() const; #endif /*! * Sets the key for the item to \a key. */ void setKey(const String &key); /*! * Sets the text value of the item to \a value and clears any previous contents. * * \see toString() */ void setValue(const String &value); /*! * Sets the text value of the item to the list of values in \a value and clears * any previous contents. * * \see toStringList() */ void setValues(const StringList &values); /*! * Appends \a value to create (or extend) the current list of text values. * * \see toString() */ void appendValue(const String &value); /*! * Appends \a values to extend the current list of text values. * * \see toStringList() */ void appendValues(const StringList &values); /*! * Returns the size of the full item. */ int size() const; /*! * Returns the value as a single string. In case of multiple strings, * the first is returned. If the data type is not \a Text, always returns * an empty String. */ String toString() const; #ifndef DO_NOT_DOCUMENT /* Remove in next binary incompatible release */ StringList toStringList() const; #endif /*! * Returns the list of text values. If the data type is not \a Text, always * returns an empty StringList. */ StringList values() const; /*! * Render the item to a ByteVector. */ ByteVector render() const; /*! * Parse the item from the ByteVector \a data. */ void parse(const ByteVector& data); /*! * Set the item to read-only. */ void setReadOnly(bool readOnly); /*! * Return true if the item is read-only. */ bool isReadOnly() const; /*! * Sets the type of the item to \a type. * * \see ItemTypes */ void setType(ItemTypes type); /*! * Returns the type of the item. */ ItemTypes type() const; /*! * Returns if the item has any real content. */ bool isEmpty() const; private: class ItemPrivate; ItemPrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apeproperties.cpp�����������������������������������������������������������0000664�0000000�0000000�00000015015�12225024651�0020362�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2010 by Alex Novichkov email : novichko@atnet.ru copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com (original WavPack implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include <bitset> #include "id3v2tag.h" #include "apeproperties.h" #include "apefile.h" using namespace TagLib; class APE::Properties::PropertiesPrivate { public: PropertiesPrivate(File *file, long streamLength) : length(0), bitrate(0), sampleRate(0), channels(0), version(0), bitsPerSample(0), sampleFrames(0), file(file), streamLength(streamLength) {} int length; int bitrate; int sampleRate; int channels; int version; int bitsPerSample; uint sampleFrames; File *file; long streamLength; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// APE::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(file, file->length()); read(); } APE::Properties::~Properties() { delete d; } int APE::Properties::length() const { return d->length; } int APE::Properties::bitrate() const { return d->bitrate; } int APE::Properties::sampleRate() const { return d->sampleRate; } int APE::Properties::channels() const { return d->channels; } int APE::Properties::version() const { return d->version; } int APE::Properties::bitsPerSample() const { return d->bitsPerSample; } TagLib::uint APE::Properties::sampleFrames() const { return d->sampleFrames; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void APE::Properties::read() { // First we are searching the descriptor long offset = findDescriptor(); if(offset < 0) return; // Then we read the header common for all versions of APE d->file->seek(offset); ByteVector commonHeader = d->file->readBlock(6); if(!commonHeader.startsWith("MAC ")) return; d->version = commonHeader.toUShort(4, false); if(d->version >= 3980) { analyzeCurrent(); } else { analyzeOld(); } } long APE::Properties::findDescriptor() { long ID3v2Location = findID3v2(); long ID3v2OriginalSize = 0; bool hasID3v2 = false; if(ID3v2Location >= 0) { ID3v2::Tag tag(d->file, ID3v2Location); ID3v2OriginalSize = tag.header()->completeTagSize(); if(tag.header()->tagSize() > 0) hasID3v2 = true; } long offset = 0; if(hasID3v2) offset = d->file->find("MAC ", ID3v2Location + ID3v2OriginalSize); else offset = d->file->find("MAC "); if(offset < 0) { debug("APE::Properties::findDescriptor() -- APE descriptor not found"); return -1; } return offset; } long APE::Properties::findID3v2() { if(!d->file->isValid()) return -1; d->file->seek(0); if(d->file->readBlock(3) == ID3v2::Header::fileIdentifier()) return 0; return -1; } void APE::Properties::analyzeCurrent() { // Read the descriptor d->file->seek(2, File::Current); ByteVector descriptor = d->file->readBlock(44); const uint descriptorBytes = descriptor.toUInt(0, false); if ((descriptorBytes - 52) > 0) d->file->seek(descriptorBytes - 52, File::Current); // Read the header ByteVector header = d->file->readBlock(24); // Get the APE info d->channels = header.toShort(18, false); d->sampleRate = header.toUInt(20, false); d->bitsPerSample = header.toShort(16, false); //d->compressionLevel = const uint totalFrames = header.toUInt(12, false); const uint blocksPerFrame = header.toUInt(4, false); const uint finalFrameBlocks = header.toUInt(8, false); d->sampleFrames = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; } void APE::Properties::analyzeOld() { ByteVector header = d->file->readBlock(26); const uint totalFrames = header.toUInt(18, false); // Fail on 0 length APE files (catches non-finalized APE files) if(totalFrames == 0) return; const short compressionLevel = header.toShort(0, false); uint blocksPerFrame; if(d->version >= 3950) blocksPerFrame = 73728 * 4; else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000)) blocksPerFrame = 73728; else blocksPerFrame = 9216; d->channels = header.toShort(4, false); d->sampleRate = header.toUInt(6, false); const uint finalFrameBlocks = header.toUInt(22, false); const uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; d->length = totalBlocks / d->sampleRate; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apeproperties.h�������������������������������������������������������������0000664�0000000�0000000�00000006312�12225024651�0020027�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2010 by Alex Novichkov email : novichko@atnet.ru copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com (original WavPack implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_APEPROPERTIES_H #define TAGLIB_APEPROPERTIES_H #include "taglib_export.h" #include "audioproperties.h" namespace TagLib { namespace APE { class File; //! An implementation of audio property reading for APE /*! * This reads the data from an APE stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of APE::Properties with the data read from the * ByteVector \a data. */ Properties(File *f, ReadStyle style = Average); /*! * Destroys this APE::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; /*! * Returns number of bits per sample. */ int bitsPerSample() const; uint sampleFrames() const; /*! * Returns APE version. */ int version() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(); long findDescriptor(); long findID3v2(); void analyzeCurrent(); void analyzeOld(); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apetag.cpp������������������������������������������������������������������0000664�0000000�0000000�00000025303�12225024651�0016742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifdef __SUNPRO_CC // Sun Studio finds multiple specializations of Map because // it considers specializations with and without class types // to be different; this define forces Map to use only the // specialization with the class keyword. #define WANT_CLASS_INSTANTIATION_OF_MAP (1) #endif #include <tfile.h> #include <tstring.h> #include <tmap.h> #include <tpropertymap.h> #include "apetag.h" #include "apefooter.h" #include "apeitem.h" using namespace TagLib; using namespace APE; class APE::Tag::TagPrivate { public: TagPrivate() : file(0), footerLocation(-1), tagLength(0) {} TagLib::File *file; long footerLocation; long tagLength; Footer footer; ItemListMap itemListMap; }; //////////////////////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////////////////////// APE::Tag::Tag() : TagLib::Tag() { d = new TagPrivate; } APE::Tag::Tag(TagLib::File *file, long footerLocation) : TagLib::Tag() { d = new TagPrivate; d->file = file; d->footerLocation = footerLocation; read(); } APE::Tag::~Tag() { delete d; } ByteVector APE::Tag::fileIdentifier() { return ByteVector::fromCString("APETAGEX"); } String APE::Tag::title() const { if(d->itemListMap["TITLE"].isEmpty()) return String::null; return d->itemListMap["TITLE"].toString(); } String APE::Tag::artist() const { if(d->itemListMap["ARTIST"].isEmpty()) return String::null; return d->itemListMap["ARTIST"].toString(); } String APE::Tag::album() const { if(d->itemListMap["ALBUM"].isEmpty()) return String::null; return d->itemListMap["ALBUM"].toString(); } String APE::Tag::comment() const { if(d->itemListMap["COMMENT"].isEmpty()) return String::null; return d->itemListMap["COMMENT"].toString(); } String APE::Tag::genre() const { if(d->itemListMap["GENRE"].isEmpty()) return String::null; return d->itemListMap["GENRE"].toString(); } TagLib::uint APE::Tag::year() const { if(d->itemListMap["YEAR"].isEmpty()) return 0; return d->itemListMap["YEAR"].toString().toInt(); } TagLib::uint APE::Tag::track() const { if(d->itemListMap["TRACK"].isEmpty()) return 0; return d->itemListMap["TRACK"].toString().toInt(); } void APE::Tag::setTitle(const String &s) { addValue("TITLE", s, true); } void APE::Tag::setArtist(const String &s) { addValue("ARTIST", s, true); } void APE::Tag::setAlbum(const String &s) { addValue("ALBUM", s, true); } void APE::Tag::setComment(const String &s) { addValue("COMMENT", s, true); } void APE::Tag::setGenre(const String &s) { addValue("GENRE", s, true); } void APE::Tag::setYear(uint i) { if(i <= 0) removeItem("YEAR"); else addValue("YEAR", String::number(i), true); } void APE::Tag::setTrack(uint i) { if(i <= 0) removeItem("TRACK"); else addValue("TRACK", String::number(i), true); } // conversions of tag keys between what we use in PropertyMap and what's usual // for APE tags static const TagLib::uint keyConversionsSize = 5; //usual, APE static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" }, {"DATE", "YEAR" }, {"ALBUMARTIST", "ALBUM ARTIST"}, {"DISCNUMBER", "DISC" }, {"REMIXER", "MIXARTIST" }}; PropertyMap APE::Tag::properties() const { PropertyMap properties; ItemListMap::ConstIterator it = itemListMap().begin(); for(; it != itemListMap().end(); ++it) { String tagName = it->first.upper(); // if the item is Binary or Locator, or if the key is an invalid string, // add to unsupportedData if(it->second.type() != Item::Text || tagName.isNull()) properties.unsupportedData().append(it->first); else { // Some tags need to be handled specially for(uint i = 0; i < keyConversionsSize; ++i) if(tagName == keyConversions[i][1]) tagName = keyConversions[i][0]; properties[tagName].append(it->second.toStringList()); } } return properties; } void APE::Tag::removeUnsupportedProperties(const StringList &properties) { StringList::ConstIterator it = properties.begin(); for(; it != properties.end(); ++it) removeItem(*it); } PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) { PropertyMap properties(origProps); // make a local copy that can be modified // see comment in properties() for(uint i = 0; i < keyConversionsSize; ++i) if(properties.contains(keyConversions[i][0])) { properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]); properties.erase(keyConversions[i][0]); } // first check if tags need to be removed completely StringList toRemove; ItemListMap::ConstIterator remIt = itemListMap().begin(); for(; remIt != itemListMap().end(); ++remIt) { String key = remIt->first.upper(); // only remove if a) key is valid, b) type is text, c) key not contained in new properties if(!key.isNull() && remIt->second.type() == APE::Item::Text && !properties.contains(key)) toRemove.append(remIt->first); } for (StringList::Iterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++) removeItem(*removeIt); // now sync in the "forward direction" PropertyMap::ConstIterator it = properties.begin(); PropertyMap invalid; for(; it != properties.end(); ++it) { const String &tagName = it->first; if(!checkKey(tagName)) invalid.insert(it->first, it->second); else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) { if(it->second.size() == 0) removeItem(tagName); else { StringList::ConstIterator valueIt = it->second.begin(); addValue(tagName, *valueIt, true); ++valueIt; for(; valueIt != it->second.end(); ++valueIt) addValue(tagName, *valueIt, false); } } } return invalid; } bool APE::Tag::checkKey(const String &key) { if(key.size() < 2 || key.size() > 16) return false; for(String::ConstIterator it = key.begin(); it != key.end(); it++) // only allow printable ASCII including space (32..127) if (*it < 32 || *it >= 128) return false; String upperKey = key.upper(); if (upperKey=="ID3" || upperKey=="TAG" || upperKey=="OGGS" || upperKey=="MP+") return false; return true; } APE::Footer *APE::Tag::footer() const { return &d->footer; } const APE::ItemListMap& APE::Tag::itemListMap() const { return d->itemListMap; } void APE::Tag::removeItem(const String &key) { Map<const String, Item>::Iterator it = d->itemListMap.find(key.upper()); if(it != d->itemListMap.end()) d->itemListMap.erase(it); } void APE::Tag::addValue(const String &key, const String &value, bool replace) { if(replace) removeItem(key); if(!key.isEmpty() && !value.isEmpty()) { if(!replace && d->itemListMap.contains(key)) { // Text items may contain more than one value if(APE::Item::Text == d->itemListMap.begin()->second.type()) d->itemListMap[key.upper()].appendValue(value); // Binary or locator items may have only one value else setItem(key, Item(key, value)); } else setItem(key, Item(key, value)); } } void APE::Tag::setData(const String &key, const ByteVector &value) { removeItem(key); if(!key.isEmpty() && !value.isEmpty()) setItem(key, Item(key, value, true)); } void APE::Tag::setItem(const String &key, const Item &item) { if(!key.isEmpty()) d->itemListMap.insert(key.upper(), item); } bool APE::Tag::isEmpty() const { return d->itemListMap.isEmpty(); } //////////////////////////////////////////////////////////////////////////////// // protected methods //////////////////////////////////////////////////////////////////////////////// void APE::Tag::read() { if(d->file && d->file->isValid()) { d->file->seek(d->footerLocation); d->footer.setData(d->file->readBlock(Footer::size())); if(d->footer.tagSize() <= Footer::size() || d->footer.tagSize() > uint(d->file->length())) return; d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize()); parse(d->file->readBlock(d->footer.tagSize() - Footer::size())); } } ByteVector APE::Tag::render() const { ByteVector data; uint itemCount = 0; { for(Map<const String, Item>::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) { data.append(it->second.render()); itemCount++; } } d->footer.setItemCount(itemCount); d->footer.setTagSize(data.size() + Footer::size()); d->footer.setHeaderPresent(true); return d->footer.renderHeader() + data + d->footer.renderFooter(); } void APE::Tag::parse(const ByteVector &data) { uint pos = 0; // 11 bytes is the minimum size for an APE item for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) { APE::Item item; item.parse(data.mid(pos)); d->itemListMap.insert(item.key().upper(), item); pos += item.size(); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ape/apetag.h��������������������������������������������������������������������0000664�0000000�0000000�00000015743�12225024651�0016416�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_APETAG_H #define TAGLIB_APETAG_H #include "tag.h" #include "tbytevector.h" #include "tmap.h" #include "tstring.h" #include "taglib_export.h" #include "apeitem.h" namespace TagLib { class File; //! An implementation of the APE tagging format namespace APE { class Footer; /*! * A mapping between a list of item names, or keys, and the associated item. * * \see APE::Tag::itemListMap() */ typedef Map<const String, Item> ItemListMap; //! An APE tag implementation class TAGLIB_EXPORT Tag : public TagLib::Tag { public: /*! * Create an APE tag with default values. */ Tag(); /*! * Create an APE tag and parse the data in \a file with APE footer at * \a tagOffset. */ Tag(TagLib::File *file, long footerLocation); /*! * Destroys this Tag instance. */ virtual ~Tag(); /*! * Renders the in memory values to a ByteVector suitable for writing to * the file. */ ByteVector render() const; /*! * Returns the string "APETAGEX" suitable for usage in locating the tag in a * file. */ static ByteVector fileIdentifier(); // Reimplementations. virtual String title() const; virtual String artist() const; virtual String album() const; virtual String comment() const; virtual String genre() const; virtual uint year() const; virtual uint track() const; virtual void setTitle(const String &s); virtual void setArtist(const String &s); virtual void setAlbum(const String &s); virtual void setComment(const String &s); virtual void setGenre(const String &s); virtual void setYear(uint i); virtual void setTrack(uint i); /*! * Implements the unified tag dictionary interface -- export function. * APE tags are perfectly compatible with the dictionary interface because they * support both arbitrary tag names and multiple values. Currently only * APE items of type *Text* are handled by the dictionary interface; all *Binary* * and *Locator* items will be put into the unsupportedData list and can be * deleted on request using removeUnsupportedProperties(). The same happens * to Text items if their key is invalid for PropertyMap (which should actually * never happen). * * The only conversion done by this export function is to rename the APE tags * TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively, * in order to be compliant with the names used in other formats. */ PropertyMap properties() const; void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified tag dictionary interface -- import function. The same * comments as for the export function apply; additionally note that the APE tag * specification requires keys to have between 2 and 16 printable ASCII characters * with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+". */ PropertyMap setProperties(const PropertyMap &); /*! * Check if the given String is a valid APE tag key. */ static bool checkKey(const String&); /*! * 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. * * APE tags are case-insensitive, all keys in this map have been converted * to upper case. * * \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 text 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. If a binary item exists for \a key it will be removed first. */ void addValue(const String &key, const String &value, bool replace = true); /*! * Set the binary data for the key specified by \a item to \a value * This will convert the item to type \a Binary if it isn't already and * all of the other values on the same key will be removed. */ void setData(const String &key, const ByteVector &value); /*! * 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); /*! * Returns true if the tag does not contain any data. */ bool isEmpty() const; 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 �����������������������������taglib-1.9.1/taglib/asf/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014776�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asfattribute.cpp������������������������������������������������������������0000664�0000000�0000000�00000017750�12225024651�0020211�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <taglib.h> #include <tdebug.h> #include "trefcounter.h" #include "asfattribute.h" #include "asffile.h" using namespace TagLib; class ASF::Attribute::AttributePrivate : public RefCounter { public: AttributePrivate() : pictureValue(ASF::Picture::fromInvalid()), stream(0), language(0) {} AttributeTypes type; String stringValue; ByteVector byteVectorValue; ASF::Picture pictureValue; union { unsigned int intValue; unsigned short shortValue; unsigned long long longLongValue; bool boolValue; }; int stream; int language; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// ASF::Attribute::Attribute() { d = new AttributePrivate; d->type = UnicodeType; } ASF::Attribute::Attribute(const ASF::Attribute &other) : d(other.d) { d->ref(); } ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) { if(d->deref()) delete d; d = other.d; d->ref(); return *this; } ASF::Attribute::~Attribute() { if(d->deref()) delete d; } ASF::Attribute::Attribute(const String &value) { d = new AttributePrivate; d->type = UnicodeType; d->stringValue = value; } ASF::Attribute::Attribute(const ByteVector &value) { d = new AttributePrivate; d->type = BytesType; d->byteVectorValue = value; } ASF::Attribute::Attribute(const ASF::Picture &value) { d = new AttributePrivate; d->type = BytesType; d->pictureValue = value; } ASF::Attribute::Attribute(unsigned int value) { d = new AttributePrivate; d->type = DWordType; d->intValue = value; } ASF::Attribute::Attribute(unsigned long long value) { d = new AttributePrivate; d->type = QWordType; d->longLongValue = value; } ASF::Attribute::Attribute(unsigned short value) { d = new AttributePrivate; d->type = WordType; d->shortValue = value; } ASF::Attribute::Attribute(bool value) { d = new AttributePrivate; d->type = BoolType; d->boolValue = value; } ASF::Attribute::AttributeTypes ASF::Attribute::type() const { return d->type; } String ASF::Attribute::toString() const { return d->stringValue; } ByteVector ASF::Attribute::toByteVector() const { if(d->pictureValue.isValid()) return d->pictureValue.render(); return d->byteVectorValue; } unsigned short ASF::Attribute::toBool() const { return d->shortValue; } unsigned short ASF::Attribute::toUShort() const { return d->shortValue; } unsigned int ASF::Attribute::toUInt() const { return d->intValue; } unsigned long long ASF::Attribute::toULongLong() const { return d->longLongValue; } ASF::Picture ASF::Attribute::toPicture() const { return d->pictureValue; } String ASF::Attribute::parse(ASF::File &f, int kind) { uint size, nameLength; String name; d->pictureValue = Picture::fromInvalid(); // extended content descriptor if(kind == 0) { nameLength = f.readWORD(); name = f.readString(nameLength); d->type = ASF::Attribute::AttributeTypes(f.readWORD()); size = f.readWORD(); } // metadata & metadata library else { int temp = f.readWORD(); // metadata library if(kind == 2) { d->language = temp; } d->stream = f.readWORD(); nameLength = f.readWORD(); d->type = ASF::Attribute::AttributeTypes(f.readWORD()); size = f.readDWORD(); name = f.readString(nameLength); } if(kind != 2 && size > 65535) { debug("ASF::Attribute::parse() -- Value larger than 64kB"); } switch(d->type) { case WordType: d->shortValue = f.readWORD(); break; case BoolType: if(kind == 0) { d->boolValue = f.readDWORD() == 1; } else { d->boolValue = f.readWORD() == 1; } break; case DWordType: d->intValue = f.readDWORD(); break; case QWordType: d->longLongValue = f.readQWORD(); break; case UnicodeType: d->stringValue = f.readString(size); break; case BytesType: case GuidType: d->byteVectorValue = f.readBlock(size); break; } if(d->type == BytesType && name == "WM/Picture") { d->pictureValue.parse(d->byteVectorValue); if(d->pictureValue.isValid()) { d->byteVectorValue.clear(); } } return name; } int ASF::Attribute::dataSize() const { switch (d->type) { case WordType: return 2; case BoolType: return 4; case DWordType: return 4; case QWordType: return 5; case UnicodeType: return d->stringValue.size() * 2 + 2; case BytesType: if(d->pictureValue.isValid()) return d->pictureValue.dataSize(); case GuidType: return d->byteVectorValue.size(); } return 0; } ByteVector ASF::Attribute::render(const String &name, int kind) const { ByteVector data; switch (d->type) { case WordType: data.append(ByteVector::fromShort(d->shortValue, false)); break; case BoolType: if(kind == 0) { data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false)); } else { data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false)); } break; case DWordType: data.append(ByteVector::fromUInt(d->intValue, false)); break; case QWordType: data.append(ByteVector::fromLongLong(d->longLongValue, false)); break; case UnicodeType: data.append(File::renderString(d->stringValue)); break; case BytesType: if(d->pictureValue.isValid()) { data.append(d->pictureValue.render()); break; } case GuidType: data.append(d->byteVectorValue); break; } if(kind == 0) { data = File::renderString(name, true) + ByteVector::fromShort((int)d->type, false) + ByteVector::fromShort(data.size(), false) + data; } else { ByteVector nameData = File::renderString(name); data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) + ByteVector::fromShort(d->stream, false) + ByteVector::fromShort(nameData.size(), false) + ByteVector::fromShort((int)d->type, false) + ByteVector::fromUInt(data.size(), false) + nameData + data; } return data; } int ASF::Attribute::language() const { return d->language; } void ASF::Attribute::setLanguage(int value) { d->language = value; } int ASF::Attribute::stream() const { return d->stream; } void ASF::Attribute::setStream(int value) { d->stream = value; } ������������������������taglib-1.9.1/taglib/asf/asfattribute.h��������������������������������������������������������������0000664�0000000�0000000�00000013350�12225024651�0017646�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ASFATTRIBUTE_H #define TAGLIB_ASFATTRIBUTE_H #include "tstring.h" #include "tbytevector.h" #include "taglib_export.h" #include "asfpicture.h" namespace TagLib { namespace ASF { class File; class Picture; class TAGLIB_EXPORT Attribute { public: /*! * Enum of types an Attribute can have. */ enum AttributeTypes { UnicodeType = 0, BytesType = 1, BoolType = 2, DWordType = 3, QWordType = 4, WordType = 5, GuidType = 6 }; /*! * Constructs an empty attribute. */ Attribute(); /*! * Constructs an attribute with \a key and a UnicodeType \a value. */ Attribute(const String &value); /*! * Constructs an attribute with \a key and a BytesType \a value. */ Attribute(const ByteVector &value); /*! * Constructs an attribute with \a key and a Picture \a value. * * This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that, * while there may be any number of APIC frames associated with a file, * only one may be of type 1 and only one may be of type 2. * * The specification also states that the description of the picture can be no longer than 64 characters, but can be empty. * WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications. * You must add code in your application to perform validations if you want to maintain complete compatibility with ID3. */ Attribute(const Picture &value); /*! * Constructs an attribute with \a key and a DWordType \a value. */ Attribute(unsigned int value); /*! * Constructs an attribute with \a key and a QWordType \a value. */ Attribute(unsigned long long value); /*! * Constructs an attribute with \a key and a WordType \a value. */ Attribute(unsigned short value); /*! * Constructs an attribute with \a key and a BoolType \a value. */ Attribute(bool value); /*! * Construct an attribute as a copy of \a other. */ Attribute(const Attribute &item); /*! * Copies the contents of \a other into this item. */ ASF::Attribute &operator=(const Attribute &other); /*! * Destroys the attribute. */ virtual ~Attribute(); /*! * Returns type of the value. */ AttributeTypes type() const; /*! * Returns the BoolType \a value. */ unsigned short toBool() const; /*! * Returns the WordType \a value. */ unsigned short toUShort() const; /*! * Returns the DWordType \a value. */ unsigned int toUInt() const; /*! * Returns the QWordType \a value. */ unsigned long long toULongLong() const; /*! * Returns the UnicodeType \a value. */ String toString() const; /*! * Returns the BytesType \a value. */ ByteVector toByteVector() const; /*! * Returns the Picture \a value. */ Picture toPicture() const; /*! * Returns the language number, or 0 is no stream number was set. */ int language() const; /*! * Sets the language number. */ void setLanguage(int value); /*! * Returns the stream number, or 0 is no stream number was set. */ int stream() const; /*! * Sets the stream number. */ void setStream(int value); #ifndef DO_NOT_DOCUMENT /* THIS IS PRIVATE, DON'T TOUCH IT! */ String parse(ASF::File &file, int kind = 0); #endif //! Returns the size of the stored data int dataSize() const; private: friend class File; ByteVector render(const String &name, int kind = 0) const; class AttributePrivate; AttributePrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asffile.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000044105�12225024651�0017117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tbytevectorlist.h> #include <tpropertymap.h> #include <tstring.h> #include "asffile.h" #include "asftag.h" #include "asfproperties.h" using namespace TagLib; class ASF::File::FilePrivate { public: FilePrivate(): size(0), tag(0), properties(0), contentDescriptionObject(0), extendedContentDescriptionObject(0), headerExtensionObject(0), metadataObject(0), metadataLibraryObject(0) {} unsigned long long size; ASF::Tag *tag; ASF::Properties *properties; List<ASF::File::BaseObject *> objects; ASF::File::ContentDescriptionObject *contentDescriptionObject; ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject; ASF::File::HeaderExtensionObject *headerExtensionObject; ASF::File::MetadataObject *metadataObject; ASF::File::MetadataLibraryObject *metadataLibraryObject; }; static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16); static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16); static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16); static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16); static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16); static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16); static ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16); static ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16); static ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16); class ASF::File::BaseObject { public: ByteVector data; virtual ~BaseObject() {} virtual ByteVector guid() = 0; virtual void parse(ASF::File *file, unsigned int size); virtual ByteVector render(ASF::File *file); }; class ASF::File::UnknownObject : public ASF::File::BaseObject { ByteVector myGuid; public: UnknownObject(const ByteVector &guid); ByteVector guid(); }; class ASF::File::FilePropertiesObject : public ASF::File::BaseObject { public: ByteVector guid(); void parse(ASF::File *file, uint size); }; class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject { public: ByteVector guid(); void parse(ASF::File *file, uint size); }; class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject { public: ByteVector guid(); void parse(ASF::File *file, uint size); ByteVector render(ASF::File *file); }; class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject { public: ByteVectorList attributeData; ByteVector guid(); void parse(ASF::File *file, uint size); ByteVector render(ASF::File *file); }; class ASF::File::MetadataObject : public ASF::File::BaseObject { public: ByteVectorList attributeData; ByteVector guid(); void parse(ASF::File *file, uint size); ByteVector render(ASF::File *file); }; class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject { public: ByteVectorList attributeData; ByteVector guid(); void parse(ASF::File *file, uint size); ByteVector render(ASF::File *file); }; class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject { public: List<ASF::File::BaseObject *> objects; ~HeaderExtensionObject(); ByteVector guid(); void parse(ASF::File *file, uint size); ByteVector render(ASF::File *file); }; ASF::File::HeaderExtensionObject::~HeaderExtensionObject() { for(unsigned int i = 0; i < objects.size(); i++) { delete objects[i]; } } void ASF::File::BaseObject::parse(ASF::File *file, unsigned int size) { data.clear(); if (size > 24 && size <= (unsigned int)(file->length())) data = file->readBlock(size - 24); else data = ByteVector::null; } ByteVector ASF::File::BaseObject::render(ASF::File * /*file*/) { return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data; } ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid) { } ByteVector ASF::File::UnknownObject::guid() { return myGuid; } ByteVector ASF::File::FilePropertiesObject::guid() { return filePropertiesGuid; } void ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size) { BaseObject::parse(file, size); file->d->properties->setLength( (int)(data.toLongLong(40, false) / 10000000L - data.toLongLong(56, false) / 1000L)); } ByteVector ASF::File::StreamPropertiesObject::guid() { return streamPropertiesGuid; } void ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size) { BaseObject::parse(file, size); file->d->properties->setChannels(data.toShort(56, false)); file->d->properties->setSampleRate(data.toUInt(58, false)); file->d->properties->setBitrate(data.toUInt(62, false) * 8 / 1000); } ByteVector ASF::File::ContentDescriptionObject::guid() { return contentDescriptionGuid; } void ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/) { file->d->contentDescriptionObject = this; int titleLength = file->readWORD(); int artistLength = file->readWORD(); int copyrightLength = file->readWORD(); int commentLength = file->readWORD(); int ratingLength = file->readWORD(); file->d->tag->setTitle(file->readString(titleLength)); file->d->tag->setArtist(file->readString(artistLength)); file->d->tag->setCopyright(file->readString(copyrightLength)); file->d->tag->setComment(file->readString(commentLength)); file->d->tag->setRating(file->readString(ratingLength)); } ByteVector ASF::File::ContentDescriptionObject::render(ASF::File *file) { ByteVector v1 = file->renderString(file->d->tag->title()); ByteVector v2 = file->renderString(file->d->tag->artist()); ByteVector v3 = file->renderString(file->d->tag->copyright()); ByteVector v4 = file->renderString(file->d->tag->comment()); ByteVector v5 = file->renderString(file->d->tag->rating()); data.clear(); data.append(ByteVector::fromShort(v1.size(), false)); data.append(ByteVector::fromShort(v2.size(), false)); data.append(ByteVector::fromShort(v3.size(), false)); data.append(ByteVector::fromShort(v4.size(), false)); data.append(ByteVector::fromShort(v5.size(), false)); data.append(v1); data.append(v2); data.append(v3); data.append(v4); data.append(v5); return BaseObject::render(file); } ByteVector ASF::File::ExtendedContentDescriptionObject::guid() { return extendedContentDescriptionGuid; } void ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/) { file->d->extendedContentDescriptionObject = this; int count = file->readWORD(); while(count--) { ASF::Attribute attribute; String name = attribute.parse(*file); file->d->tag->addAttribute(name, attribute); } } ByteVector ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file) { data.clear(); data.append(ByteVector::fromShort(attributeData.size(), false)); data.append(attributeData.toByteVector(ByteVector::null)); return BaseObject::render(file); } ByteVector ASF::File::MetadataObject::guid() { return metadataGuid; } void ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/) { file->d->metadataObject = this; int count = file->readWORD(); while(count--) { ASF::Attribute attribute; String name = attribute.parse(*file, 1); file->d->tag->addAttribute(name, attribute); } } ByteVector ASF::File::MetadataObject::render(ASF::File *file) { data.clear(); data.append(ByteVector::fromShort(attributeData.size(), false)); data.append(attributeData.toByteVector(ByteVector::null)); return BaseObject::render(file); } ByteVector ASF::File::MetadataLibraryObject::guid() { return metadataLibraryGuid; } void ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/) { file->d->metadataLibraryObject = this; int count = file->readWORD(); while(count--) { ASF::Attribute attribute; String name = attribute.parse(*file, 2); file->d->tag->addAttribute(name, attribute); } } ByteVector ASF::File::MetadataLibraryObject::render(ASF::File *file) { data.clear(); data.append(ByteVector::fromShort(attributeData.size(), false)); data.append(attributeData.toByteVector(ByteVector::null)); return BaseObject::render(file); } ByteVector ASF::File::HeaderExtensionObject::guid() { return headerExtensionGuid; } void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/) { file->d->headerExtensionObject = this; file->seek(18, File::Current); long long dataSize = file->readDWORD(); long long dataPos = 0; while(dataPos < dataSize) { ByteVector guid = file->readBlock(16); if(guid.size() != 16) { file->setValid(false); break; } bool ok; long long size = file->readQWORD(&ok); if(!ok) { file->setValid(false); break; } BaseObject *obj; if(guid == metadataGuid) { obj = new MetadataObject(); } else if(guid == metadataLibraryGuid) { obj = new MetadataLibraryObject(); } else { obj = new UnknownObject(guid); } obj->parse(file, (unsigned int)size); objects.append(obj); dataPos += size; } } ByteVector ASF::File::HeaderExtensionObject::render(ASF::File *file) { data.clear(); for(unsigned int i = 0; i < objects.size(); i++) { data.append(objects[i]->render(file)); } data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data; return BaseObject::render(file); } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } ASF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } ASF::File::~File() { for(unsigned int i = 0; i < d->objects.size(); i++) { delete d->objects[i]; } if(d->tag) { delete d->tag; } if(d->properties) { delete d->properties; } delete d; } ASF::Tag *ASF::File::tag() const { return d->tag; } PropertyMap ASF::File::properties() const { return d->tag->properties(); } void ASF::File::removeUnsupportedProperties(const StringList &properties) { d->tag->removeUnsupportedProperties(properties); } PropertyMap ASF::File::setProperties(const PropertyMap &properties) { return d->tag->setProperties(properties); } ASF::Properties *ASF::File::audioProperties() const { return d->properties; } void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/) { if(!isValid()) return; ByteVector guid = readBlock(16); if(guid != headerGuid) { debug("ASF: Not an ASF file."); setValid(false); return; } d->tag = new ASF::Tag(); d->properties = new ASF::Properties(); bool ok; d->size = readQWORD(&ok); if(!ok) { setValid(false); return; } int numObjects = readDWORD(&ok); if(!ok) { setValid(false); return; } seek(2, Current); for(int i = 0; i < numObjects; i++) { ByteVector guid = readBlock(16); if(guid.size() != 16) { setValid(false); break; } long size = (long)readQWORD(&ok); if(!ok) { setValid(false); break; } BaseObject *obj; if(guid == filePropertiesGuid) { obj = new FilePropertiesObject(); } else if(guid == streamPropertiesGuid) { obj = new StreamPropertiesObject(); } else if(guid == contentDescriptionGuid) { obj = new ContentDescriptionObject(); } else if(guid == extendedContentDescriptionGuid) { obj = new ExtendedContentDescriptionObject(); } else if(guid == headerExtensionGuid) { obj = new HeaderExtensionObject(); } else { if(guid == contentEncryptionGuid || guid == extendedContentEncryptionGuid || guid == advancedContentEncryptionGuid) { d->properties->setEncrypted(true); } obj = new UnknownObject(guid); } obj->parse(this, size); d->objects.append(obj); } } bool ASF::File::save() { if(readOnly()) { debug("ASF::File::save() -- File is read only."); return false; } if(!isValid()) { debug("ASF::File::save() -- Trying to save invalid file."); return false; } if(!d->contentDescriptionObject) { d->contentDescriptionObject = new ContentDescriptionObject(); d->objects.append(d->contentDescriptionObject); } if(!d->extendedContentDescriptionObject) { d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject(); d->objects.append(d->extendedContentDescriptionObject); } if(!d->headerExtensionObject) { d->headerExtensionObject = new HeaderExtensionObject(); d->objects.append(d->headerExtensionObject); } if(!d->metadataObject) { d->metadataObject = new MetadataObject(); d->headerExtensionObject->objects.append(d->metadataObject); } if(!d->metadataLibraryObject) { d->metadataLibraryObject = new MetadataLibraryObject(); d->headerExtensionObject->objects.append(d->metadataLibraryObject); } ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin(); for(; it != d->tag->attributeListMap().end(); it++) { const String &name = it->first; const AttributeList &attributes = it->second; bool inExtendedContentDescriptionObject = false; bool inMetadataObject = false; for(unsigned int j = 0; j < attributes.size(); j++) { const Attribute &attribute = attributes[j]; bool largeValue = attribute.dataSize() > 65535; if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) { d->extendedContentDescriptionObject->attributeData.append(attribute.render(name)); inExtendedContentDescriptionObject = true; } else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) { d->metadataObject->attributeData.append(attribute.render(name, 1)); inMetadataObject = true; } else { d->metadataLibraryObject->attributeData.append(attribute.render(name, 2)); } } } ByteVector data; for(unsigned int i = 0; i < d->objects.size(); i++) { data.append(d->objects[i]->render(this)); } data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data; insert(data, 0, (TagLib::ulong)d->size); return true; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// int ASF::File::readBYTE(bool *ok) { ByteVector v = readBlock(1); if(v.size() != 1) { if(ok) *ok = false; return 0; } if(ok) *ok = true; return v[0]; } int ASF::File::readWORD(bool *ok) { ByteVector v = readBlock(2); if(v.size() != 2) { if(ok) *ok = false; return 0; } if(ok) *ok = true; return v.toUShort(false); } unsigned int ASF::File::readDWORD(bool *ok) { ByteVector v = readBlock(4); if(v.size() != 4) { if(ok) *ok = false; return 0; } if(ok) *ok = true; return v.toUInt(false); } long long ASF::File::readQWORD(bool *ok) { ByteVector v = readBlock(8); if(v.size() != 8) { if(ok) *ok = false; return 0; } if(ok) *ok = true; return v.toLongLong(false); } String ASF::File::readString(int length) { ByteVector data = readBlock(length); unsigned int size = data.size(); while (size >= 2) { if(data[size - 1] != '\0' || data[size - 2] != '\0') { break; } size -= 2; } if(size != data.size()) { data.resize(size); } return String(data, String::UTF16LE); } ByteVector ASF::File::renderString(const String &str, bool includeLength) { ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false); if(includeLength) { data = ByteVector::fromShort(data.size(), false) + data; } return data; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asffile.h�������������������������������������������������������������������0000664�0000000�0000000�00000012224�12225024651�0016561�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ASFFILE_H #define TAGLIB_ASFFILE_H #include "tag.h" #include "tfile.h" #include "taglib_export.h" #include "asfproperties.h" #include "asftag.h" namespace TagLib { //! An implementation of ASF (WMA) metadata namespace ASF { /*! * This implements and provides an interface for ASF files to the * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * the abstract TagLib::File API as well as providing some additional * information specific to ASF files. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * Constructs an ASF file from \a file. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an ASF file from \a stream. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. */ File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); /*! * Returns a pointer to the ASF tag of the file. * * ASF::Tag implements the tag interface, so this serves as the * reimplementation of TagLib::File::tag(). * * \note The Tag <b>is still</b> owned by the ASF::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. */ virtual Tag *tag() const; /*! * Implements the unified property interface -- export function. */ PropertyMap properties() const; /*! * Removes unsupported properties. Forwards to the actual Tag's * removeUnsupportedProperties() function. */ void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the ASF audio properties for this file. */ virtual Properties *audioProperties() const; /*! * Save the file. * * This returns true if the save was successful. */ virtual bool save(); private: int readBYTE(bool *ok = 0); int readWORD(bool *ok = 0); unsigned int readDWORD(bool *ok = 0); long long readQWORD(bool *ok = 0); static ByteVector renderString(const String &str, bool includeLength = false); String readString(int len); void read(bool readProperties, Properties::ReadStyle propertiesStyle); friend class Attribute; friend class Picture; class BaseObject; class UnknownObject; class FilePropertiesObject; class StreamPropertiesObject; class ContentDescriptionObject; class ExtendedContentDescriptionObject; class HeaderExtensionObject; class MetadataObject; class MetadataLibraryObject; class FilePrivate; FilePrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asfpicture.cpp��������������������������������������������������������������0000664�0000000�0000000�00000010651�12225024651�0017652�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Anton Sergunov email : setosha@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <taglib.h> #include <tdebug.h> #include "trefcounter.h" #include "asfattribute.h" #include "asffile.h" #include "asfpicture.h" using namespace TagLib; class ASF::Picture::PicturePrivate : public RefCounter { public: bool valid; Type type; String mimeType; String description; ByteVector picture; }; //////////////////////////////////////////////////////////////////////////////// // Picture class members //////////////////////////////////////////////////////////////////////////////// ASF::Picture::Picture() { d = new PicturePrivate(); d->valid = true; } ASF::Picture::Picture(const Picture& other) : d(other.d) { d->ref(); } ASF::Picture::~Picture() { if(d->deref()) delete d; } bool ASF::Picture::isValid() const { return d->valid; } String ASF::Picture::mimeType() const { return d->mimeType; } void ASF::Picture::setMimeType(const String &value) { d->mimeType = value; } ASF::Picture::Type ASF::Picture::type() const { return d->type; } void ASF::Picture::setType(const ASF::Picture::Type& t) { d->type = t; } String ASF::Picture::description() const { return d->description; } void ASF::Picture::setDescription(const String &desc) { d->description = desc; } ByteVector ASF::Picture::picture() const { return d->picture; } void ASF::Picture::setPicture(const ByteVector &p) { d->picture = p; } int ASF::Picture::dataSize() const { return 9 + (d->mimeType.length() + d->description.length()) * 2 + d->picture.size(); } ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other) { if(other.d != d) { if(d->deref()) delete d; d = other.d; d->ref(); } return *this; } ByteVector ASF::Picture::render() const { if(!isValid()) return ByteVector::null; return ByteVector((char)d->type) + ByteVector::fromUInt(d->picture.size(), false) + ASF::File::renderString(d->mimeType) + ASF::File::renderString(d->description) + d->picture; } void ASF::Picture::parse(const ByteVector& bytes) { d->valid = false; if(bytes.size() < 9) return; int pos = 0; d->type = (Type)bytes[0]; ++pos; const uint dataLen = bytes.toUInt(pos, false); pos+=4; const ByteVector nullStringTerminator(2, 0); int endPos = bytes.find(nullStringTerminator, pos, 2); if(endPos < 0) return; d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE); pos = endPos+2; endPos = bytes.find(nullStringTerminator, pos, 2); if(endPos < 0) return; d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE); pos = endPos+2; if(dataLen + pos != bytes.size()) return; d->picture = bytes.mid(pos, dataLen); d->valid = true; return; } ASF::Picture ASF::Picture::fromInvalid() { Picture ret; ret.d->valid = false; return ret; } ���������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asfpicture.h����������������������������������������������������������������0000664�0000000�0000000�00000015552�12225024651�0017324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Anton Sergunov email : setosha@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef ASFPICTURE_H #define ASFPICTURE_H #include "tstring.h" #include "tbytevector.h" #include "taglib_export.h" #include "attachedpictureframe.h" namespace TagLib { namespace ASF { //! An ASF attached picture interface implementation /*! * This is an implementation of ASF attached pictures interface. Pictures may be * included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture * attribute in a single tag). These pictures are usually in either JPEG or * PNG format. * \see Attribute::toPicture() * \see Attribute::Attribute(const Picture& picture) */ class TAGLIB_EXPORT Picture { 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. */ Picture(); /*! * Construct an picture as a copy of \a other. */ Picture(const Picture& other); /*! * Destroys the picture. */ virtual ~Picture(); /*! * Copies the contents of \a other into this picture. */ Picture& operator=(const Picture& other); /*! * Returns true if Picture stores valid picture */ bool isValid() const; /*! * Returns the mime type of the image. This should in most cases be * "image/png" or "image/jpeg". * \see setMimeType(const String &) * \see picture() * \see setPicture(const ByteArray&) */ String mimeType() const; /*! * Sets the mime type of the image. This should in most cases be * "image/png" or "image/jpeg". * \see setMimeType(const String &) * \see picture() * \see setPicture(const ByteArray&) */ void setMimeType(const String &value); /*! * 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(const ASF::Picture::Type& t); /*! * Returns a text description of the image. * * \see setDescription() */ String description() const; /*! * Sets a textual description of the image to \a desc. * * \see description() */ void setDescription(const String &desc); /*! * 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); /*! * Returns picture as binary raw data \a value */ ByteVector render() const; /*! * Returns picture as binary raw data \a value */ int dataSize() const; #ifndef DO_NOT_DOCUMENT /* THIS IS PRIVATE, DON'T TOUCH IT! */ void parse(const ByteVector& ); static Picture fromInvalid(); friend class Attribute; #endif private: class PicturePrivate; PicturePrivate *d; }; } } #endif // ASFPICTURE_H ������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asfproperties.cpp�����������������������������������������������������������0000664�0000000�0000000�00000006332�12225024651�0020374�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tstring.h> #include "asfproperties.h" using namespace TagLib; class ASF::Properties::PropertiesPrivate { public: PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0), encrypted(false) {} int length; int bitrate; int sampleRate; int channels; bool encrypted; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// ASF::Properties::Properties() : AudioProperties(AudioProperties::Average) { d = new PropertiesPrivate; } ASF::Properties::~Properties() { if(d) delete d; } int ASF::Properties::length() const { return d->length; } int ASF::Properties::bitrate() const { return d->bitrate; } int ASF::Properties::sampleRate() const { return d->sampleRate; } int ASF::Properties::channels() const { return d->channels; } bool ASF::Properties::isEncrypted() const { return d->encrypted; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void ASF::Properties::setLength(int length) { d->length = length; } void ASF::Properties::setBitrate(int length) { d->bitrate = length; } void ASF::Properties::setSampleRate(int length) { d->sampleRate = length; } void ASF::Properties::setChannels(int length) { d->channels = length; } void ASF::Properties::setEncrypted(bool encrypted) { d->encrypted = encrypted; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asfproperties.h�������������������������������������������������������������0000664�0000000�0000000�00000005253�12225024651�0020042�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ASFPROPERTIES_H #define TAGLIB_ASFPROPERTIES_H #include "audioproperties.h" #include "tstring.h" #include "taglib_export.h" namespace TagLib { namespace ASF { //! An implementation of ASF audio properties class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of ASF::Properties. */ Properties(); /*! * Destroys this ASF::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; bool isEncrypted() const; #ifndef DO_NOT_DOCUMENT void setLength(int value); void setBitrate(int value); void setSampleRate(int value); void setChannels(int value); void setEncrypted(bool value); #endif private: class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asftag.cpp������������������������������������������������������������������0000664�0000000�0000000�00000022561�12225024651�0016755�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tpropertymap.h> #include "asftag.h" using namespace TagLib; class ASF::Tag::TagPrivate { public: String title; String artist; String copyright; String comment; String rating; AttributeListMap attributeListMap; }; ASF::Tag::Tag() : TagLib::Tag() { d = new TagPrivate; } ASF::Tag::~Tag() { if(d) delete d; } String ASF::Tag::title() const { return d->title; } String ASF::Tag::artist() const { return d->artist; } String ASF::Tag::album() const { if(d->attributeListMap.contains("WM/AlbumTitle")) return d->attributeListMap["WM/AlbumTitle"][0].toString(); return String::null; } String ASF::Tag::copyright() const { return d->copyright; } String ASF::Tag::comment() const { return d->comment; } String ASF::Tag::rating() const { return d->rating; } unsigned int ASF::Tag::year() const { if(d->attributeListMap.contains("WM/Year")) return d->attributeListMap["WM/Year"][0].toString().toInt(); return 0; } unsigned int ASF::Tag::track() const { if(d->attributeListMap.contains("WM/TrackNumber")) { const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0]; if(attr.type() == ASF::Attribute::DWordType) return attr.toUInt(); else return attr.toString().toInt(); } if(d->attributeListMap.contains("WM/Track")) return d->attributeListMap["WM/Track"][0].toUInt(); return 0; } String ASF::Tag::genre() const { if(d->attributeListMap.contains("WM/Genre")) return d->attributeListMap["WM/Genre"][0].toString(); return String::null; } void ASF::Tag::setTitle(const String &value) { d->title = value; } void ASF::Tag::setArtist(const String &value) { d->artist = value; } void ASF::Tag::setCopyright(const String &value) { d->copyright = value; } void ASF::Tag::setComment(const String &value) { d->comment = value; } void ASF::Tag::setRating(const String &value) { d->rating = value; } void ASF::Tag::setAlbum(const String &value) { setAttribute("WM/AlbumTitle", value); } void ASF::Tag::setGenre(const String &value) { setAttribute("WM/Genre", value); } void ASF::Tag::setYear(uint value) { setAttribute("WM/Year", String::number(value)); } void ASF::Tag::setTrack(uint value) { setAttribute("WM/TrackNumber", String::number(value)); } ASF::AttributeListMap& ASF::Tag::attributeListMap() { return d->attributeListMap; } void ASF::Tag::removeItem(const String &key) { AttributeListMap::Iterator it = d->attributeListMap.find(key); if(it != d->attributeListMap.end()) d->attributeListMap.erase(it); } void ASF::Tag::setAttribute(const String &name, const Attribute &attribute) { AttributeList value; value.append(attribute); d->attributeListMap.insert(name, value); } void ASF::Tag::addAttribute(const String &name, const Attribute &attribute) { if(d->attributeListMap.contains(name)) { d->attributeListMap[name].append(attribute); } else { setAttribute(name, attribute); } } bool ASF::Tag::isEmpty() const { return TagLib::Tag::isEmpty() && copyright().isEmpty() && rating().isEmpty() && d->attributeListMap.isEmpty(); } static const char *keyTranslation[][2] = { { "WM/AlbumTitle", "ALBUM" }, { "WM/Composer", "COMPOSER" }, { "WM/Writer", "WRITER" }, { "WM/Conductor", "CONDUCTOR" }, { "WM/ModifiedBy", "REMIXER" }, { "WM/Year", "DATE" }, { "WM/OriginalReleaseYear", "ORIGINALDATE" }, { "WM/Producer", "PRODUCER" }, { "WM/ContentGroupDescription", "GROUPING" }, { "WM/SubTitle", "SUBTITLE" }, { "WM/SetSubTitle", "DISCSUBTITLE" }, { "WM/TrackNumber", "TRACKNUMBER" }, { "WM/PartOfSet", "DISCNUMBER" }, { "WM/Genre", "GENRE" }, { "WM/BeatsPerMinute", "BPM" }, { "WM/Mood", "MOOD" }, { "WM/ISRC", "ISRC" }, { "WM/Lyrics", "LYRICS" }, { "WM/Media", "MEDIA" }, { "WM/Publisher", "LABEL" }, { "WM/CatalogNo", "CATALOGNUMBER" }, { "WM/Barcode", "BARCODE" }, { "WM/EncodedBy", "ENCODEDBY" }, { "WM/AlbumSortOrder", "ALBUMSORT" }, { "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" }, { "WM/ArtistSortOrder", "ARTISTSORT" }, { "WM/TitleSortOrder", "TITLESORT" }, { "WM/Script", "SCRIPT" }, { "WM/Language", "LANGUAGE" }, { "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" }, { "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" }, { "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" }, { "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, { "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, { "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" }, { "MusicIP/PUID", "MUSICIP_PUID" }, { "Acoustid/Id", "ACOUSTID_ID" }, { "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" }, }; PropertyMap ASF::Tag::properties() const { static Map<String, String> keyMap; if(keyMap.isEmpty()) { int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); for(int i = 0; i < numKeys; i++) { keyMap[keyTranslation[i][0]] = keyTranslation[i][1]; } } PropertyMap props; if(!d->title.isEmpty()) { props["TITLE"] = d->title; } if(!d->artist.isEmpty()) { props["ARTIST"] = d->artist; } if(!d->copyright.isEmpty()) { props["COPYRIGHT"] = d->copyright; } if(!d->comment.isEmpty()) { props["COMMENT"] = d->comment; } ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin(); for(; it != d->attributeListMap.end(); ++it) { if(keyMap.contains(it->first)) { String key = keyMap[it->first]; AttributeList::ConstIterator it2 = it->second.begin(); for(; it2 != it->second.end(); ++it2) { if(key == "TRACKNUMBER") { if(it2->type() == ASF::Attribute::DWordType) props.insert(key, String::number(it2->toUInt())); else props.insert(key, it2->toString()); } else { props.insert(key, it2->toString()); } } } else { props.unsupportedData().append(it->first); } } return props; } void ASF::Tag::removeUnsupportedProperties(const StringList &props) { StringList::ConstIterator it = props.begin(); for(; it != props.end(); ++it) d->attributeListMap.erase(*it); } PropertyMap ASF::Tag::setProperties(const PropertyMap &props) { static Map<String, String> reverseKeyMap; if(reverseKeyMap.isEmpty()) { int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); for(int i = 0; i < numKeys; i++) { reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0]; } } PropertyMap origProps = properties(); PropertyMap::ConstIterator it = origProps.begin(); for(; it != origProps.end(); ++it) { if(!props.contains(it->first) || props[it->first].isEmpty()) { if(it->first == "TITLE") { d->title = String::null; } else if(it->first == "ARTIST") { d->artist = String::null; } else if(it->first == "COMMENT") { d->comment = String::null; } else if(it->first == "COPYRIGHT") { d->copyright = String::null; } else { d->attributeListMap.erase(reverseKeyMap[it->first]); } } } PropertyMap ignoredProps; it = props.begin(); for(; it != props.end(); ++it) { if(reverseKeyMap.contains(it->first)) { String name = reverseKeyMap[it->first]; removeItem(name); StringList::ConstIterator it2 = it->second.begin(); for(; it2 != it->second.end(); ++it2) { addAttribute(name, *it2); } } else if(it->first == "TITLE") { d->title = it->second.toString(); } else if(it->first == "ARTIST") { d->artist = it->second.toString(); } else if(it->first == "COMMENT") { d->comment = it->second.toString(); } else if(it->first == "COPYRIGHT") { d->copyright = it->second.toString(); } else { ignoredProps.insert(it->first, it->second); } } return ignoredProps; } �����������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/asf/asftag.h��������������������������������������������������������������������0000664�0000000�0000000�00000013144�12225024651�0016417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2005-2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ASFTAG_H #define TAGLIB_ASFTAG_H #include "tag.h" #include "tlist.h" #include "tmap.h" #include "taglib_export.h" #include "asfattribute.h" namespace TagLib { namespace ASF { typedef List<Attribute> AttributeList; typedef Map<String, AttributeList> AttributeListMap; class TAGLIB_EXPORT Tag : public TagLib::Tag { friend class File; public: Tag(); virtual ~Tag(); /*! * Returns the track name. */ virtual String title() const; /*! * Returns the artist name. */ virtual String artist() const; /*! * Returns the album name; if no album name is present in the tag * String::null will be returned. */ virtual String album() const; /*! * Returns the track comment. */ virtual String comment() const; /*! * Returns the genre name; if no genre is present in the tag String::null * will be returned. */ virtual String genre() const; /*! * Returns the rating. */ virtual String rating() const; /*! * Returns the genre name; if no genre is present in the tag String::null * will be returned. */ virtual String copyright() const; /*! * Returns the year; if there is no year set, this will return 0. */ virtual uint year() const; /*! * Returns the track number; if there is no track number set, this will * return 0. */ virtual uint track() const; /*! * Sets the title to \a s. */ virtual void setTitle(const String &s); /*! * Sets the artist to \a s. */ virtual void setArtist(const String &s); /*! * Sets the album to \a s. If \a s is String::null then this value will be * cleared. */ virtual void setAlbum(const String &s); /*! * Sets the comment to \a s. */ virtual void setComment(const String &s); /*! * Sets the rating to \a s. */ virtual void setRating(const String &s); /*! * Sets the copyright to \a s. */ virtual void setCopyright(const String &s); /*! * Sets the genre to \a s. */ virtual void setGenre(const String &s); /*! * Sets the year to \a i. If \a s is 0 then this value will be cleared. */ virtual void setYear(uint i); /*! * Sets the track to \a i. If \a s is 0 then this value will be cleared. */ virtual void setTrack(uint i); /*! * Returns true if the tag does not contain any data. This should be * reimplemented in subclasses that provide more than the basic tagging * abilities in this class. */ virtual bool isEmpty() const; /*! * Returns a reference to the item list map. This is an AttributeListMap of * all of the items in the tag. * * This is the most powerfull structure for accessing the items of the tag. */ AttributeListMap &attributeListMap(); /*! * Removes the \a key attribute from the tag */ void removeItem(const String &name); /*! * Sets the \a key attribute to the value of \a attribute. If an attribute * with the \a key is already present, it will be replaced. */ void setAttribute(const String &name, const Attribute &attribute); /*! * Sets the \a key attribute to the value of \a attribute. If an attribute * with the \a key is already present, it will be added to the list. */ void addAttribute(const String &name, const Attribute &attribute); PropertyMap properties() const; void removeUnsupportedProperties(const StringList& properties); PropertyMap setProperties(const PropertyMap &properties); private: class TagPrivate; TagPrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/audioproperties.cpp�������������������������������������������������������������0000664�0000000�0000000�00000004360�12225024651�0020152�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "audioproperties.h" using namespace TagLib; class AudioProperties::AudioPropertiesPrivate { }; //////////////////////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////////////////////// AudioProperties::~AudioProperties() { } //////////////////////////////////////////////////////////////////////////////// // protected methods //////////////////////////////////////////////////////////////////////////////// AudioProperties::AudioProperties(ReadStyle) { } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/audioproperties.h���������������������������������������������������������������0000664�0000000�0000000�00000007747�12225024651�0017633�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_AUDIOPROPERTIES_H #define TAGLIB_AUDIOPROPERTIES_H #include "taglib_export.h" namespace TagLib { //! A simple, abstract interface to common audio properties /*! * The values here are common to most audio formats. For more specific, codec * dependant values, please see see the subclasses APIs. This is meant to * compliment the TagLib::File and TagLib::Tag APIs in providing a simple * interface that is sufficient for most applications. */ class TAGLIB_EXPORT AudioProperties { public: /*! * Reading audio properties from a file can sometimes be very time consuming * and for the most accurate results can often involve reading the entire * file. Because in many situations speed is critical or the accuracy of the * values is not particularly important this allows the level of desired * accuracy to be set. */ enum ReadStyle { //! Read as little of the file as possible Fast, //! Read more of the file and make better values guesses Average, //! Read as much of the file as needed to report accurate values Accurate }; /*! * Destroys this AudioProperties instance. */ virtual ~AudioProperties(); /*! * Returns the length of the file in seconds. */ virtual int length() const = 0; /*! * Returns the most appropriate bit rate for the file in kb/s. For constant * bitrate formats this is simply the bitrate of the file. For variable * bitrate formats this is either the average or nominal bitrate. */ virtual int bitrate() const = 0; /*! * Returns the sample rate in Hz. */ virtual int sampleRate() const = 0; /*! * Returns the number of audio channels. */ virtual int channels() const = 0; protected: /*! * Construct an audio properties instance. This is protected as this class * should not be instantiated directly, but should be instantiated via its * subclasses and can be fetched from the FileRef or File APIs. * * \see ReadStyle */ AudioProperties(ReadStyle style); private: AudioProperties(const AudioProperties &); AudioProperties &operator=(const AudioProperties &); class AudioPropertiesPrivate; AudioPropertiesPrivate *d; }; } #endif �������������������������taglib-1.9.1/taglib/fileref.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000020507�12225024651�0016351�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org copyright : (C) 2010 by Alex Novichkov email : novichko@atnet.ru (added APE file support) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tfile.h> #include <tstring.h> #include <tdebug.h> #include "trefcounter.h" #include "fileref.h" #include "asffile.h" #include "mpegfile.h" #include "vorbisfile.h" #include "flacfile.h" #include "oggflacfile.h" #include "mpcfile.h" #include "mp4file.h" #include "wavpackfile.h" #include "speexfile.h" #include "opusfile.h" #include "trueaudiofile.h" #include "aifffile.h" #include "wavfile.h" #include "apefile.h" #include "modfile.h" #include "s3mfile.h" #include "itfile.h" #include "xmfile.h" using namespace TagLib; class FileRef::FileRefPrivate : public RefCounter { public: FileRefPrivate(File *f) : RefCounter(), file(f) {} ~FileRefPrivate() { delete file; } File *file; static List<const FileTypeResolver *> fileTypeResolvers; }; List<const FileRef::FileTypeResolver *> FileRef::FileRefPrivate::fileTypeResolvers; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// FileRef::FileRef() { d = new FileRefPrivate(0); } FileRef::FileRef(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) { d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle)); } FileRef::FileRef(File *file) { d = new FileRefPrivate(file); } FileRef::FileRef(const FileRef &ref) : d(ref.d) { d->ref(); } FileRef::~FileRef() { if(d->deref()) delete d; } Tag *FileRef::tag() const { if(isNull()) { debug("FileRef::tag() - Called without a valid file."); return 0; } return d->file->tag(); } AudioProperties *FileRef::audioProperties() const { if(isNull()) { debug("FileRef::audioProperties() - Called without a valid file."); return 0; } return d->file->audioProperties(); } File *FileRef::file() const { return d->file; } bool FileRef::save() { if(isNull()) { debug("FileRef::save() - Called without a valid file."); return false; } return d->file->save(); } const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static { FileRefPrivate::fileTypeResolvers.prepend(resolver); return resolver; } StringList FileRef::defaultFileExtensions() { StringList l; l.append("ogg"); l.append("flac"); l.append("oga"); l.append("mp3"); l.append("mpc"); l.append("wv"); l.append("spx"); l.append("tta"); l.append("m4a"); l.append("m4r"); l.append("m4b"); l.append("m4p"); l.append("3g2"); l.append("mp4"); l.append("wma"); l.append("asf"); l.append("aif"); l.append("aiff"); l.append("wav"); l.append("ape"); l.append("mod"); l.append("module"); // alias for "mod" l.append("nst"); // alias for "mod" l.append("wow"); // alias for "mod" l.append("s3m"); l.append("it"); l.append("xm"); return l; } bool FileRef::isNull() const { return !d->file || !d->file->isValid(); } FileRef &FileRef::operator=(const FileRef &ref) { if(&ref == this) return *this; if(d->deref()) delete d; d = ref.d; d->ref(); return *this; } bool FileRef::operator==(const FileRef &ref) const { return ref.d->file == d->file; } bool FileRef::operator!=(const FileRef &ref) const { return ref.d->file != d->file; } File *FileRef::create(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) // static { List<const FileTypeResolver *>::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin(); for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) { File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle); if(file) return file; } // Ok, this is really dumb for now, but it works for testing. String ext; { #ifdef _WIN32 String s = fileName.toString(); #else String s = fileName; #endif const int pos = s.rfind("."); if(pos != -1) ext = s.substr(pos + 1).upper(); } // If this list is updated, the method defaultFileExtensions() should also be // updated. However at some point that list should be created at the same time // that a default file type resolver is created. if(!ext.isEmpty()) { if(ext == "MP3") return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "OGG") return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "OGA") { /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); if (file->isValid()) return file; delete file; return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); } if(ext == "FLAC") return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "MPC") return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WV") return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "SPX") return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "OPUS") return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "TTA") return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WMA" || ext == "ASF") return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "AIF" || ext == "AIFF") return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "WAV") return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "APE") return new APE::File(fileName, readAudioProperties, audioPropertiesStyle); // module, nst and wow are possible but uncommon extensions if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "S3M") return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "IT") return new IT::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "XM") return new XM::File(fileName, readAudioProperties, audioPropertiesStyle); } return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/fileref.h�����������������������������������������������������������������������0000664�0000000�0000000�00000022244�12225024651�0016016�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FILEREF_H #define TAGLIB_FILEREF_H #include "tfile.h" #include "tstringlist.h" #include "taglib_export.h" #include "audioproperties.h" namespace TagLib { class Tag; //! This class provides a simple abstraction for creating and handling files /*! * FileRef exists to provide a minimal, generic and value-based wrapper around * a File. It is lightweight and implicitly shared, and as such suitable for * pass-by-value use. This hides some of the uglier details of TagLib::File * and the non-generic portions of the concrete file implementations. * * This class is useful in a "simple usage" situation where it is desirable * to be able to get and set some of the tag information that is similar * across file types. * * Also note that it is probably a good idea to plug this into your mime * type system rather than using the constructor that accepts a file name using * the FileTypeResolver. * * \see FileTypeResolver * \see addFileTypeResolver() */ class TAGLIB_EXPORT FileRef { public: //! A class for pluggable file type resolution. /*! * This class is used to add extend TagLib's very basic file name based file * type resolution. * * This can be accomplished with: * * \code * * class MyFileTypeResolver : FileTypeResolver * { * TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle) * { * if(someCheckForAnMP3File(fileName)) * return new TagLib::MPEG::File(fileName); * return 0; * } * } * * FileRef::addFileTypeResolver(new MyFileTypeResolver); * * \endcode * * Naturally a less contrived example would be slightly more complex. This * can be used to plug in mime-type detection systems or to add new file types * to TagLib. */ class TAGLIB_EXPORT FileTypeResolver { TAGLIB_IGNORE_MISSING_DESTRUCTOR public: /*! * This method must be overridden to provide an additional file type * resolver. If the resolver is able to determine the file type it should * return a valid File object; if not it should return 0. * * \note The created file is then owned by the FileRef and should not be * deleted. Deletion will happen automatically when the FileRef passes * out of scope. */ virtual File *createFile(FileName fileName, bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average) const = 0; }; /*! * Creates a null FileRef. */ FileRef(); /*! * Create a FileRef from \a fileName. If \a readAudioProperties is true then * the audio properties will be read using \a audioPropertiesStyle. If * \a readAudioProperties is false then \a audioPropertiesStyle will be * ignored. * * Also see the note in the class documentation about why you may not want to * use this method in your application. */ explicit FileRef(FileName fileName, bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); /*! * Contruct a FileRef using \a file. The FileRef now takes ownership of the * pointer and will delete the File when it passes out of scope. */ explicit FileRef(File *file); /*! * Make a copy of \a ref. */ FileRef(const FileRef &ref); /*! * Destroys this FileRef instance. */ virtual ~FileRef(); /*! * Returns a pointer to represented file's tag. * * \warning This pointer will become invalid when this FileRef and all * copies pass out of scope. * * \warning Do not cast it to any subclasses of \class Tag. * Use tag returning methods of appropriate subclasses of \class File instead. * * \see File::tag() */ Tag *tag() const; /*! * Returns the audio properties for this FileRef. If no audio properties * were read then this will returns a null pointer. */ AudioProperties *audioProperties() const; /*! * Returns a pointer to the file represented by this handler class. * * As a general rule this call should be avoided since if you need to work * with file objects directly, you are probably better served instantiating * the File subclasses (i.e. MPEG::File) manually and working with their APIs. * * This <i>handle</i> exists to provide a minimal, generic and value-based * wrapper around a File. Accessing the file directly generally indicates * a moving away from this simplicity (and into things beyond the scope of * FileRef). * * \warning This pointer will become invalid when this FileRef and all * copies pass out of scope. */ File *file() const; /*! * Saves the file. Returns true on success. */ bool save(); /*! * Adds a FileTypeResolver to the list of those used by TagLib. Each * additional FileTypeResolver is added to the front of a list of resolvers * that are tried. If the FileTypeResolver returns zero the next resolver * is tried. * * Returns a pointer to the added resolver (the same one that's passed in -- * this is mostly so that static inialializers have something to use for * assignment). * * \see FileTypeResolver */ static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver); /*! * As is mentioned elsewhere in this class's documentation, the default file * type resolution code provided by TagLib only works by comparing file * extensions. * * This method returns the list of file extensions that are used by default. * * The extensions are all returned in lowercase, though the comparison used * by TagLib for resolution is case-insensitive. * * \note This does not account for any additional file type resolvers that * are plugged in. Also note that this is not intended to replace a propper * mime-type resolution system, but is just here for reference. * * \see FileTypeResolver */ static StringList defaultFileExtensions(); /*! * Returns true if the file (and as such other pointers) are null. */ bool isNull() const; /*! * Assign the file pointed to by \a ref to this FileRef. */ FileRef &operator=(const FileRef &ref); /*! * Returns true if this FileRef and \a ref point to the same File object. */ bool operator==(const FileRef &ref) const; /*! * Returns true if this FileRef and \a ref do not point to the same File * object. */ bool operator!=(const FileRef &ref) const; /*! * A simple implementation of file type guessing. If \a readAudioProperties * is true then the audio properties will be read using * \a audioPropertiesStyle. If \a readAudioProperties is false then * \a audioPropertiesStyle will be ignored. * * \note You generally shouldn't use this method, but instead the constructor * directly. * * \deprecated */ static File *create(FileName fileName, bool readAudioProperties = true, AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); private: class FileRefPrivate; FileRefPrivate *d; }; } // namespace TagLib #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015132�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacfile.cpp���������������������������������������������������������������0000664�0000000�0000000�00000034063�12225024651�0017411�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tstring.h> #include <tlist.h> #include <tdebug.h> #include <tagunion.h> #include <tpropertymap.h> #include <id3v2header.h> #include <id3v2tag.h> #include <id3v1tag.h> #include <xiphcomment.h> #include "flacpicture.h" #include "flacfile.h" #include "flacmetadatablock.h" #include "flacunknownmetadatablock.h" using namespace TagLib; namespace { enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 }; enum { MinPaddingLength = 4096 }; enum { LastBlockFlag = 0x80 }; } class FLAC::File::FilePrivate { public: FilePrivate() : ID3v2FrameFactory(ID3v2::FrameFactory::instance()), ID3v2Location(-1), ID3v2OriginalSize(0), ID3v1Location(-1), properties(0), flacStart(0), streamStart(0), streamLength(0), scanned(false), hasXiphComment(false), hasID3v2(false), hasID3v1(false) { } ~FilePrivate() { uint size = blocks.size(); for(uint i = 0; i < size; i++) { delete blocks[i]; } delete properties; } const ID3v2::FrameFactory *ID3v2FrameFactory; long ID3v2Location; uint ID3v2OriginalSize; long ID3v1Location; TagUnion tag; Properties *properties; ByteVector streamInfoData; ByteVector xiphCommentData; List<MetadataBlock *> blocks; long flacStart; long streamStart; long streamLength; bool scanned; bool hasXiphComment; bool hasID3v2; bool hasID3v1; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// FLAC::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; d->ID3v2FrameFactory = frameFactory; if(isOpen()) read(readProperties, propertiesStyle); } FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate; d->ID3v2FrameFactory = frameFactory; if(isOpen()) read(readProperties, propertiesStyle); } FLAC::File::~File() { delete d; } TagLib::Tag *FLAC::File::tag() const { return &d->tag; } PropertyMap FLAC::File::properties() const { // once Tag::properties() is virtual, this case distinction could actually be done // within TagUnion. if(d->hasXiphComment) return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->properties(); if(d->hasID3v2) return d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->properties(); if(d->hasID3v1) return d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->properties(); return PropertyMap(); } void FLAC::File::removeUnsupportedProperties(const StringList &unsupported) { if(d->hasXiphComment) d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->removeUnsupportedProperties(unsupported); if(d->hasID3v2) d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->removeUnsupportedProperties(unsupported); if(d->hasID3v1) d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->removeUnsupportedProperties(unsupported); } PropertyMap FLAC::File::setProperties(const PropertyMap &properties) { return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, true)->setProperties(properties); } 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; } if(!isValid()) { debug("FLAC::File::save() -- Trying to save invalid file."); return false; } // Create new vorbis comments Tag::duplicate(&d->tag, xiphComment(true), false); d->xiphCommentData = xiphComment()->render(false); // Replace metadata blocks bool foundVorbisCommentBlock = false; List<MetadataBlock *> newBlocks; for(uint i = 0; i < d->blocks.size(); i++) { MetadataBlock *block = d->blocks[i]; if(block->code() == MetadataBlock::VorbisComment) { // Set the new Vorbis Comment block delete block; block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData); foundVorbisCommentBlock = true; } if(block->code() == MetadataBlock::Padding) { delete block; continue; } newBlocks.append(block); } if(!foundVorbisCommentBlock) { newBlocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)); foundVorbisCommentBlock = true; } d->blocks = newBlocks; // Render data for the metadata blocks ByteVector data; for(uint i = 0; i < newBlocks.size(); i++) { FLAC::MetadataBlock *block = newBlocks[i]; ByteVector blockData = block->render(); ByteVector blockHeader = ByteVector::fromUInt(blockData.size()); blockHeader[0] = block->code(); data.append(blockHeader); data.append(blockData); } // Adjust the padding block(s) long originalLength = d->streamStart - d->flacStart; int paddingLength = originalLength - data.size() - 4; if (paddingLength < 0) { paddingLength = MinPaddingLength; } ByteVector padding = ByteVector::fromUInt(paddingLength); padding.resize(paddingLength + 4); padding[0] = (char)(FLAC::MetadataBlock::Padding | LastBlockFlag); data.append(padding); // Write the data to the file insert(data, d->flacStart, originalLength); d->hasXiphComment = true; // Update ID3 tags if(ID3v2Tag()) { if(d->hasID3v2) { if(d->ID3v2Location < d->flacStart) debug("FLAC::File::save() -- This can't be right -- an ID3v2 tag after the " "start of the FLAC bytestream? Not writing the ID3v2 tag."); else insert(ID3v2Tag()->render(), d->ID3v2Location, d->ID3v2OriginalSize); } else insert(ID3v2Tag()->render(), 0, 0); } if(ID3v1Tag()) { seek(-128, End); writeBlock(ID3v1Tag()->render()); } return true; } ID3v2::Tag *FLAC::File::ID3v2Tag(bool create) { if(!create || d->tag[FlacID3v2Index]) return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]); d->tag.set(FlacID3v2Index, new ID3v2::Tag); return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]); } ID3v1::Tag *FLAC::File::ID3v1Tag(bool create) { return d->tag.access<ID3v1::Tag>(FlacID3v1Index, create); } Ogg::XiphComment *FLAC::File::xiphComment(bool create) { return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create); } void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) { d->ID3v2FrameFactory = factory; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { // Look for an ID3v2 tag d->ID3v2Location = findID3v2(); if(d->ID3v2Location >= 0) { d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); if(ID3v2Tag()->header()->tagSize() <= 0) d->tag.set(FlacID3v2Index, 0); else d->hasID3v2 = true; } // Look for an ID3v1 tag d->ID3v1Location = findID3v1(); if(d->ID3v1Location >= 0) { d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); d->hasID3v1 = true; } // Look for FLAC metadata, including vorbis comments scan(); if(!isValid()) return; if(d->hasXiphComment) d->tag.set(FlacXiphIndex, new Ogg::XiphComment(xiphCommentData())); else d->tag.set(FlacXiphIndex, new Ogg::XiphComment); if(readProperties) d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle); } ByteVector FLAC::File::streamInfoData() { return isValid() ? d->streamInfoData : ByteVector(); } ByteVector FLAC::File::xiphCommentData() const { return (isValid() && d->hasXiphComment) ? d->xiphCommentData : ByteVector(); } long FLAC::File::streamLength() { return d->streamLength; } void FLAC::File::scan() { // Scan the metadata pages if(d->scanned) return; if(!isValid()) return; long nextBlockOffset; if(d->hasID3v2) nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize); else nextBlockOffset = find("fLaC"); if(nextBlockOffset < 0) { debug("FLAC::File::scan() -- FLAC stream not found"); setValid(false); return; } nextBlockOffset += 4; d->flacStart = nextBlockOffset; seek(nextBlockOffset); ByteVector header = readBlock(4); // Header format (from spec): // <1> Last-metadata-block flag // <7> BLOCK_TYPE // 0 : STREAMINFO // 1 : PADDING // .. // 4 : VORBIS_COMMENT // .. // <24> Length of metadata to follow char blockType = header[0] & 0x7f; bool isLastBlock = (header[0] & 0x80) != 0; uint length = header.toUInt(1U, 3U); // First block should be the stream_info metadata if(blockType != MetadataBlock::StreamInfo) { debug("FLAC::File::scan() -- invalid FLAC stream"); setValid(false); return; } d->streamInfoData = readBlock(length); d->blocks.append(new UnknownMetadataBlock(blockType, d->streamInfoData)); nextBlockOffset += length + 4; // Search through the remaining metadata while(!isLastBlock) { header = readBlock(4); blockType = header[0] & 0x7f; isLastBlock = (header[0] & 0x80) != 0; length = header.toUInt(1U, 3U); ByteVector data = readBlock(length); if(data.size() != length || length == 0) { debug("FLAC::File::scan() -- FLAC stream corrupted"); setValid(false); return; } MetadataBlock *block = 0; // Found the vorbis-comment if(blockType == MetadataBlock::VorbisComment) { if(!d->hasXiphComment) { d->xiphCommentData = data; d->hasXiphComment = true; } else { debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one"); } } else if(blockType == MetadataBlock::Picture) { FLAC::Picture *picture = new FLAC::Picture(); if(picture->parse(data)) { block = picture; } else { debug("FLAC::File::scan() -- invalid picture found, discarting"); delete picture; } } if(!block) { block = new UnknownMetadataBlock(blockType, data); } if(block->code() != MetadataBlock::Padding) { d->blocks.append(block); } else { delete block; } nextBlockOffset += length + 4; if(nextBlockOffset >= File::length()) { debug("FLAC::File::scan() -- FLAC stream corrupted"); setValid(false); return; } seek(nextBlockOffset); } // End of metadata, now comes the datastream d->streamStart = nextBlockOffset; d->streamLength = File::length() - d->streamStart; if(d->hasID3v1) d->streamLength -= 128; d->scanned = true; } long FLAC::File::findID3v1() { if(!isValid()) return -1; seek(-128, End); long p = tell(); if(readBlock(3) == ID3v1::Tag::fileIdentifier()) return p; return -1; } long FLAC::File::findID3v2() { if(!isValid()) return -1; seek(0); if(readBlock(3) == ID3v2::Header::fileIdentifier()) return 0; return -1; } List<FLAC::Picture *> FLAC::File::pictureList() { List<Picture *> pictures; for(uint i = 0; i < d->blocks.size(); i++) { Picture *picture = dynamic_cast<Picture *>(d->blocks[i]); if(picture) { pictures.append(picture); } } return pictures; } void FLAC::File::addPicture(Picture *picture) { d->blocks.append(picture); } void FLAC::File::removePicture(Picture *picture, bool del) { MetadataBlock *block = picture; List<MetadataBlock *>::Iterator it = d->blocks.find(block); if(it != d->blocks.end()) d->blocks.erase(it); if(del) delete picture; } void FLAC::File::removePictures() { List<MetadataBlock *> newBlocks; for(uint i = 0; i < d->blocks.size(); i++) { Picture *picture = dynamic_cast<Picture *>(d->blocks[i]); if(picture) { delete picture; } else { newBlocks.append(d->blocks[i]); } } d->blocks = newBlocks; } bool FLAC::File::hasXiphComment() const { return d->hasXiphComment; } bool FLAC::File::hasID3v1Tag() const { return d->hasID3v1; } bool FLAC::File::hasID3v2Tag() const { return d->hasID3v2; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacfile.h�����������������������������������������������������������������0000664�0000000�0000000�00000025613�12225024651�0017057�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FLACFILE_H #define TAGLIB_FLACFILE_H #include "taglib_export.h" #include "tfile.h" #include "tlist.h" #include "tag.h" #include "flacpicture.h" #include "flacproperties.h" namespace TagLib { class Tag; namespace ID3v2 { class FrameFactory; class Tag; } namespace ID3v1 { class Tag; } namespace Ogg { class XiphComment; } //! An implementation of FLAC metadata /*! * This is implementation of FLAC metadata for non-Ogg FLAC files. At some * point when Ogg / FLAC is more common there will be a similar implementation * under the Ogg hiearchy. * * This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream * properties from the file. */ namespace FLAC { //! An implementation of TagLib::File with FLAC specific methods /*! * This implements and provides an interface for FLAC files to the * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * the abstract TagLib::File API as well as providing some additional * information specific to FLAC files. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * Constructs a FLAC file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. * * \deprecated This constructor will be dropped in favor of the one below * in a future version. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an APE file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * If this file contains and ID3v2 tag the frames will be created using * \a frameFactory. * * \note In the current implementation, \a propertiesStyle is ignored. */ // BIC: merge with the above constructor File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs a FLAC file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * If this file contains and ID3v2 tag the frames will be created using * \a frameFactory. * * \note In the current implementation, \a propertiesStyle is ignored. */ // BIC: merge with the above constructor File(IOStream *stream, 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; /*! * Implements the unified property interface -- export function. * If the file contains more than one tag (e.g. XiphComment and ID3v1), * only the first one (in the order XiphComment, ID3v2, ID3v1) will be * converted to the PropertyMap. */ PropertyMap properties() const; void removeUnsupportedProperties(const StringList &); /*! * Implements the unified property interface -- import function. * This always creates a Xiph comment, if none exists. The return value * relates to the Xiph comment only. * Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed * in the FLAC specification. */ PropertyMap setProperties(const PropertyMap &); /*! * 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 returns 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file * on disk actually has an ID3v2 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v2Tag() */ ID3v2::Tag *ID3v2Tag(bool create = false); /*! * Returns a pointer to the ID3v1 tag of the file. * * If \a create is false (the default) this returns 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file * on disk actually has an ID3v1 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v1Tag() */ ID3v1::Tag *ID3v1Tag(bool create = false); /*! * Returns a pointer to the XiphComment for the file. * * If \a create is false (the default) this returns a null pointer * if there is no valid XiphComment. If \a create is true it will create * a XiphComment if one does not exist and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has a XiphComment. Use hasXiphComment() to check if the * file on disk actually has a XiphComment. * * \note The Tag <b>is still</b> owned by the FLAC::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasXiphComment() */ 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 /*! * Returns a list of pictures attached to the FLAC file. */ List<Picture *> pictureList(); /*! * Removes an attached picture. If \a del is true the picture's memory * will be freed; if it is false, it must be deleted by the user. */ void removePicture(Picture *picture, bool del = true); /*! * Remove all attached images. */ void removePictures(); /*! * Add a new picture to the file. The file takes ownership of the * picture and will handle freeing its memory. * * \note The file will be saved only after calling save(). */ void addPicture(Picture *picture); /*! * Returns whether or not the file on disk actually has a XiphComment. * * \see xiphComment() */ bool hasXiphComment() const; /*! * Returns whether or not the file on disk actually has an ID3v1 tag. * * \see ID3v1Tag() */ bool hasID3v1Tag() const; /*! * Returns whether or not the file on disk actually has an ID3v2 tag. * * \see ID3v2Tag() */ bool hasID3v2Tag() const; private: File(const File &); File &operator=(const File &); void read(bool readProperties, Properties::ReadStyle propertiesStyle); void scan(); long findID3v2(); long findID3v1(); ByteVector xiphCommentData() const; long findPaddingBreak(long nextPageOffset, long targetOffset, bool *isLast); class FilePrivate; FilePrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacmetadatablock.cpp������������������������������������������������������0000664�0000000�0000000�00000003724�12225024651�0021265�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <taglib.h> #include <tdebug.h> #include "flacmetadatablock.h" using namespace TagLib; class FLAC::MetadataBlock::MetadataBlockPrivate { public: MetadataBlockPrivate() {} }; FLAC::MetadataBlock::MetadataBlock() { d = 0; } FLAC::MetadataBlock::~MetadataBlock() { } ��������������������������������������������taglib-1.9.1/taglib/flac/flacmetadatablock.h��������������������������������������������������������0000664�0000000�0000000�00000005061�12225024651�0020726�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FLACMETADATABLOCK_H #define TAGLIB_FLACMETADATABLOCK_H #include "tlist.h" #include "tbytevector.h" #include "taglib_export.h" namespace TagLib { namespace FLAC { class TAGLIB_EXPORT MetadataBlock { public: MetadataBlock(); virtual ~MetadataBlock(); enum BlockType { StreamInfo = 0, Padding, Application, SeekTable, VorbisComment, CueSheet, Picture }; /*! * Returns the FLAC metadata block type. */ virtual int code() const = 0; /*! * Render the content of the block. */ virtual ByteVector render() const = 0; private: MetadataBlock(const MetadataBlock &item); MetadataBlock &operator=(const MetadataBlock &item); class MetadataBlockPrivate; MetadataBlockPrivate *d; }; } } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacpicture.cpp������������������������������������������������������������0000664�0000000�0000000�00000012473�12225024651�0020146�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <taglib.h> #include <tdebug.h> #include "flacpicture.h" using namespace TagLib; class FLAC::Picture::PicturePrivate { public: PicturePrivate() : type(FLAC::Picture::Other), width(0), height(0), colorDepth(0), numColors(0) {} Type type; String mimeType; String description; int width; int height; int colorDepth; int numColors; ByteVector data; }; FLAC::Picture::Picture() { d = new PicturePrivate; } FLAC::Picture::Picture(const ByteVector &data) { d = new PicturePrivate; parse(data); } FLAC::Picture::~Picture() { delete d; } int FLAC::Picture::code() const { return FLAC::MetadataBlock::Picture; } bool FLAC::Picture::parse(const ByteVector &data) { if(data.size() < 32) { debug("A picture block must contain at least 5 bytes."); return false; } uint pos = 0; d->type = FLAC::Picture::Type(data.toUInt(pos)); pos += 4; uint mimeTypeLength = data.toUInt(pos); pos += 4; if(pos + mimeTypeLength + 24 > data.size()) { debug("Invalid picture block."); return false; } d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8); pos += mimeTypeLength; uint descriptionLength = data.toUInt(pos); pos += 4; if(pos + descriptionLength + 20 > data.size()) { debug("Invalid picture block."); return false; } d->description = String(data.mid(pos, descriptionLength), String::UTF8); pos += descriptionLength; d->width = data.toUInt(pos); pos += 4; d->height = data.toUInt(pos); pos += 4; d->colorDepth = data.toUInt(pos); pos += 4; d->numColors = data.toUInt(pos); pos += 4; uint dataLength = data.toUInt(pos); pos += 4; if(pos + dataLength > data.size()) { debug("Invalid picture block."); return false; } d->data = data.mid(pos, dataLength); return true; } ByteVector FLAC::Picture::render() const { ByteVector result; result.append(ByteVector::fromUInt(d->type)); ByteVector mimeTypeData = d->mimeType.data(String::UTF8); result.append(ByteVector::fromUInt(mimeTypeData.size())); result.append(mimeTypeData); ByteVector descriptionData = d->description.data(String::UTF8); result.append(ByteVector::fromUInt(descriptionData.size())); result.append(descriptionData); result.append(ByteVector::fromUInt(d->width)); result.append(ByteVector::fromUInt(d->height)); result.append(ByteVector::fromUInt(d->colorDepth)); result.append(ByteVector::fromUInt(d->numColors)); result.append(ByteVector::fromUInt(d->data.size())); result.append(d->data); return result; } FLAC::Picture::Type FLAC::Picture::type() const { return d->type; } void FLAC::Picture::setType(FLAC::Picture::Type type) { d->type = type; } String FLAC::Picture::mimeType() const { return d->mimeType; } void FLAC::Picture::setMimeType(const String &mimeType) { d->mimeType = mimeType; } String FLAC::Picture::description() const { return d->description; } void FLAC::Picture::setDescription(const String &description) { d->description = description; } int FLAC::Picture::width() const { return d->width; } void FLAC::Picture::setWidth(int width) { d->width = width; } int FLAC::Picture::height() const { return d->height; } void FLAC::Picture::setHeight(int height) { d->height = height; } int FLAC::Picture::colorDepth() const { return d->colorDepth; } void FLAC::Picture::setColorDepth(int colorDepth) { d->colorDepth = colorDepth; } int FLAC::Picture::numColors() const { return d->numColors; } void FLAC::Picture::setNumColors(int numColors) { d->numColors = numColors; } ByteVector FLAC::Picture::data() const { return d->data; } void FLAC::Picture::setData(const ByteVector &data) { d->data = data; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacpicture.h��������������������������������������������������������������0000664�0000000�0000000�00000014164�12225024651�0017612�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FLACPICTURE_H #define TAGLIB_FLACPICTURE_H #include "tlist.h" #include "tstring.h" #include "tbytevector.h" #include "taglib_export.h" #include "flacmetadatablock.h" namespace TagLib { namespace FLAC { class TAGLIB_EXPORT Picture : public MetadataBlock { 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 }; Picture(); Picture(const ByteVector &data); ~Picture(); /*! * Returns the type of the image. */ Type type() const; /*! * Sets the type of the image. */ void setType(Type type); /*! * 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 a text description of the image. */ String description() const; /*! * Sets a textual description of the image to \a desc. */ void setDescription(const String &desc); /*! * Returns the width of the image. */ int width() const; /*! * Sets the width of the image. */ void setWidth(int w); /*! * Returns the height of the image. */ int height() const; /*! * Sets the height of the image. */ void setHeight(int h); /*! * Returns the color depth (in bits-per-pixel) of the image. */ int colorDepth() const; /*! * Sets the color depth (in bits-per-pixel) of the image. */ void setColorDepth(int depth); /*! * Returns the number of colors used on the image.. */ int numColors() const; /*! * Sets the number of colors used on the image (for indexed images). */ void setNumColors(int numColors); /*! * Returns the image data. */ ByteVector data() const; /*! * Sets the image data. */ void setData(const ByteVector &data); /*! * Returns the FLAC metadata block type. */ int code() const; /*! * Render the content to the FLAC picture block format. */ ByteVector render() const; /*! * Parse the picture data in the FLAC picture block format. */ bool parse(const ByteVector &rawData); private: Picture(const Picture &item); Picture &operator=(const Picture &item); class PicturePrivate; PicturePrivate *d; }; typedef List<Picture> PictureList; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacproperties.cpp���������������������������������������������������������0000664�0000000�0000000�00000011177�12225024651�0020667�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include "flacproperties.h" #include "flacfile.h" using namespace TagLib; class FLAC::Properties::PropertiesPrivate { public: PropertiesPrivate(ByteVector d, long st, ReadStyle s) : data(d), streamLength(st), style(s), length(0), bitrate(0), sampleRate(0), sampleWidth(0), channels(0), sampleFrames(0) {} ByteVector data; long streamLength; ReadStyle style; int length; int bitrate; int sampleRate; int sampleWidth; int channels; unsigned long long sampleFrames; ByteVector signature; }; //////////////////////////////////////////////////////////////////////////////// // 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; } unsigned long long FLAC::Properties::sampleFrames() const { return d->sampleFrames; } ByteVector FLAC::Properties::signature() const { return d->signature; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void FLAC::Properties::read() { if(d->data.size() < 18) { debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes."); return; } uint 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.toUInt(pos, true); pos += 4; 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) unsigned long long hi = flags & 0xf; unsigned long long lo = d->data.toUInt(pos, true); pos += 4; d->sampleFrames = (hi << 32) | lo; if(d->sampleRate > 0) d->length = int(d->sampleFrames / d->sampleRate); // Uncompressed bitrate: //d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth; // Real bitrate: d->bitrate = d->length > 0 ? ((d->streamLength * 8UL) / d->length) / 1000 : 0; d->signature = d->data.mid(pos, 32); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacproperties.h�����������������������������������������������������������0000664�0000000�0000000�00000006663�12225024651�0020340�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FLACPROPERTIES_H #define TAGLIB_FLACPROPERTIES_H #include "taglib_export.h" #include "audioproperties.h" namespace TagLib { namespace FLAC { class File; //! An implementation of audio property reading for FLAC /*! * This reads the data from an FLAC stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of FLAC::Properties with the data read from the * ByteVector \a data. */ // BIC: switch to const reference Properties(ByteVector data, long streamLength, ReadStyle style = Average); /*! * Create an instance of FLAC::Properties with the data read from the * FLAC::File \a file. */ // BIC: remove Properties(File *file, ReadStyle style = Average); /*! * Destroys this FLAC::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; /*! * Returns the sample width as read from the FLAC identification * header. */ int sampleWidth() const; /*! * Return the number of sample frames */ unsigned long long sampleFrames() const; /*! * Returns the MD5 signature of the uncompressed audio stream as read * from the stream info header header. */ ByteVector signature() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif �����������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacunknownmetadatablock.cpp�����������������������������������������������0000664�0000000�0000000�00000005127�12225024651�0022704�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <taglib.h> #include <tdebug.h> #include <tstring.h> #include "flacunknownmetadatablock.h" using namespace TagLib; class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate { public: UnknownMetadataBlockPrivate() : code(0) {} int code; ByteVector data; }; FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) { d = new UnknownMetadataBlockPrivate; d->code = code; //debug(String(data.toHex())); d->data = data; } FLAC::UnknownMetadataBlock::~UnknownMetadataBlock() { delete d; } int FLAC::UnknownMetadataBlock::code() const { return d->code; } void FLAC::UnknownMetadataBlock::setCode(int code) { d->code = code; } ByteVector FLAC::UnknownMetadataBlock::data() const { return d->data; } void FLAC::UnknownMetadataBlock::setData(const ByteVector &data) { d->data = data; } ByteVector FLAC::UnknownMetadataBlock::render() const { return d->data; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/flac/flacunknownmetadatablock.h�������������������������������������������������0000664�0000000�0000000�00000005457�12225024651�0022357�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2010 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FLACUNKNOWNMETADATABLOCK_H #define TAGLIB_FLACUNKNOWNMETADATABLOCK_H #include "tlist.h" #include "tbytevector.h" #include "taglib_export.h" #include "flacmetadatablock.h" namespace TagLib { namespace FLAC { class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock { public: UnknownMetadataBlock(int blockType, const ByteVector &data); ~UnknownMetadataBlock(); /*! * Returns the FLAC metadata block type. */ int code() const; /*! * Sets the FLAC metadata block type. */ void setCode(int code); /*! * Returns the FLAC metadata block type. */ ByteVector data() const; /*! * Sets the FLAC metadata block type. */ void setData(const ByteVector &data); /*! * Render the content of the block. */ ByteVector render() const; private: UnknownMetadataBlock(const MetadataBlock &item); UnknownMetadataBlock &operator=(const MetadataBlock &item); class UnknownMetadataBlockPrivate; UnknownMetadataBlockPrivate *d; }; } } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/it/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014641�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/it/itfile.cpp�������������������������������������������������������������������0000664�0000000�0000000�00000022362�12225024651�0016626�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "tstringlist.h" #include "itfile.h" #include "tdebug.h" #include "modfileprivate.h" #include "tpropertymap.h" using namespace TagLib; using namespace IT; class IT::File::FilePrivate { public: FilePrivate(AudioProperties::ReadStyle propertiesStyle) : tag(), properties(propertiesStyle) { } Mod::Tag tag; IT::Properties properties; }; IT::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } IT::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } IT::File::~File() { delete d; } Mod::Tag *IT::File::tag() const { return &d->tag; } PropertyMap IT::File::properties() const { return d->tag.properties(); } PropertyMap IT::File::setProperties(const PropertyMap &properties) { return d->tag.setProperties(properties); } IT::Properties *IT::File::audioProperties() const { return &d->properties; } bool IT::File::save() { if(readOnly()) { debug("IT::File::save() - Cannot save to a read only file."); return false; } seek(4); writeString(d->tag.title(), 25); writeByte(0); seek(2, Current); ushort length = 0; ushort instrumentCount = 0; ushort sampleCount = 0; if(!readU16L(length) || !readU16L(instrumentCount) || !readU16L(sampleCount)) return false; seek(15, Current); // write comment as instrument and sample names: StringList lines = d->tag.comment().split("\n"); for(ushort i = 0; i < instrumentCount; ++ i) { seek(192L + length + ((long)i << 2)); ulong instrumentOffset = 0; if(!readU32L(instrumentOffset)) return false; seek(instrumentOffset + 32); if(i < lines.size()) writeString(lines[i], 25); else writeString(String::null, 25); writeByte(0); } for(ushort i = 0; i < sampleCount; ++ i) { seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2)); ulong sampleOffset = 0; if(!readU32L(sampleOffset)) return false; seek(sampleOffset + 20); if((TagLib::uint)(i + instrumentCount) < lines.size()) writeString(lines[i + instrumentCount], 25); else writeString(String::null, 25); writeByte(0); } // write rest as message: StringList messageLines; for(uint i = instrumentCount + sampleCount; i < lines.size(); ++ i) messageLines.append(lines[i]); ByteVector message = messageLines.toString("\r").data(String::Latin1); // it's actually not really stated if the message needs a // terminating NUL but it does not hurt to add one: if(message.size() > 7999) message.resize(7999); message.append((char)0); ushort special = 0; ushort messageLength = 0; ulong messageOffset = 0; seek(46); if(!readU16L(special)) return false; ulong fileSize = File::length(); if(special & Properties::MessageAttached) { seek(54); if(!readU16L(messageLength) || !readU32L(messageOffset)) return false; if(messageLength == 0) messageOffset = fileSize; } else { messageOffset = fileSize; seek(46); writeU16L(special | 0x1); } if(messageOffset + messageLength >= fileSize) { // append new message seek(54); writeU16L(message.size()); writeU32L(messageOffset); seek(messageOffset); writeBlock(message); truncate(messageOffset + message.size()); } else { // Only overwrite existing message. // I'd need to parse (understand!) the whole file for more. // Although I could just move the message to the end of file // and let the existing one be, but that would waste space. message.resize(messageLength, 0); seek(messageOffset); writeBlock(message); } return true; } void IT::File::read(bool) { if(!isOpen()) return; seek(0); READ_ASSERT(readBlock(4) == "IMPM"); READ_STRING(d->tag.setTitle, 26); seek(2, Current); READ_U16L_AS(length); READ_U16L_AS(instrumentCount); READ_U16L_AS(sampleCount); d->properties.setInstrumentCount(instrumentCount); d->properties.setSampleCount(sampleCount); READ_U16L(d->properties.setPatternCount); READ_U16L(d->properties.setVersion); READ_U16L(d->properties.setCompatibleVersion); READ_U16L(d->properties.setFlags); READ_U16L_AS(special); d->properties.setSpecial(special); READ_BYTE(d->properties.setGlobalVolume); READ_BYTE(d->properties.setMixVolume); READ_BYTE(d->properties.setBpmSpeed); READ_BYTE(d->properties.setTempo); READ_BYTE(d->properties.setPanningSeparation); READ_BYTE(d->properties.setPitchWheelDepth); // IT supports some kind of comment tag. Still, the // sample/instrument names are abused as comments so // I just add all together. String message; if(special & Properties::MessageAttached) { READ_U16L_AS(messageLength); READ_U32L_AS(messageOffset); seek(messageOffset); ByteVector messageBytes = readBlock(messageLength); READ_ASSERT(messageBytes.size() == messageLength); int index = messageBytes.find((char) 0); if(index > -1) messageBytes.resize(index, 0); messageBytes.replace('\r', '\n'); message = messageBytes; } seek(64); ByteVector pannings = readBlock(64); ByteVector volumes = readBlock(64); READ_ASSERT(pannings.size() == 64 && volumes.size() == 64); int channels = 0; for(int i = 0; i < 64; ++ i) { // Strictly speaking an IT file has always 64 channels, but // I don't count disabled and muted channels. // But this always gives 64 channels for all my files anyway. // Strangely VLC does report other values. I wonder how VLC // gets it's values. if((unsigned char) pannings[i] < 128 && volumes[i] > 0) ++channels; } d->properties.setChannels(channels); // real length might be shorter because of skips and terminator ushort realLength = 0; for(ushort i = 0; i < length; ++ i) { READ_BYTE_AS(order); if(order == 255) break; if(order != 254) ++ realLength; } d->properties.setLengthInPatterns(realLength); StringList comment; // Note: I found files that have nil characters somewhere // in the instrument/sample names and more characters // afterwards. The spec does not mention such a case. // Currently I just discard anything after a nil, but // e.g. VLC seems to interprete a nil as a space. I // don't know what is the proper behaviour. for(ushort i = 0; i < instrumentCount; ++ i) { seek(192L + length + ((long)i << 2)); READ_U32L_AS(instrumentOffset); seek(instrumentOffset); ByteVector instrumentMagic = readBlock(4); READ_ASSERT(instrumentMagic == "IMPI"); READ_STRING_AS(dosFileName, 13); seek(15, Current); READ_STRING_AS(instrumentName, 26); comment.append(instrumentName); } for(ushort i = 0; i < sampleCount; ++ i) { seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2)); READ_U32L_AS(sampleOffset); seek(sampleOffset); ByteVector sampleMagic = readBlock(4); READ_ASSERT(sampleMagic == "IMPS"); READ_STRING_AS(dosFileName, 13); READ_BYTE_AS(globalVolume); READ_BYTE_AS(sampleFlags); READ_BYTE_AS(sampleVolume); READ_STRING_AS(sampleName, 26); /* READ_BYTE_AS(sampleCvt); READ_BYTE_AS(samplePanning); READ_U32L_AS(sampleLength); READ_U32L_AS(loopStart); READ_U32L_AS(loopStop); READ_U32L_AS(c5speed); READ_U32L_AS(sustainLoopStart); READ_U32L_AS(sustainLoopEnd); READ_U32L_AS(sampleDataOffset); READ_BYTE_AS(vibratoSpeed); READ_BYTE_AS(vibratoDepth); READ_BYTE_AS(vibratoRate); READ_BYTE_AS(vibratoType); */ comment.append(sampleName); } if(message.size() > 0) comment.append(message); d->tag.setComment(comment.toString("\n")); d->tag.setTrackerName("Impulse Tracker"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/it/itfile.h���������������������������������������������������������������������0000664�0000000�0000000�00000007401�12225024651�0016270�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_ITFILE_H #define TAGLIB_ITFILE_H #include "tfile.h" #include "audioproperties.h" #include "taglib_export.h" #include "modfilebase.h" #include "modtag.h" #include "itproperties.h" namespace TagLib { namespace IT { class TAGLIB_EXPORT File : public Mod::FileBase { public: /*! * Constructs a Impulse Tracker file from \a file. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. */ File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Constructs a Impulse Tracker file from \a stream. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. */ File(IOStream *stream, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); Mod::Tag *tag() const; /*! * Forwards to Mod::Tag::properties(). * BIC: will be removed once File::toDict() is made virtual */ PropertyMap properties() const; /*! * Forwards to Mod::Tag::setProperties(). * BIC: will be removed once File::setProperties() is made virtual */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the IT::Properties for this file. If no audio properties * were read then this will return a null pointer. */ IT::Properties *audioProperties() const; /*! * Save the file. * This is the same as calling save(AllTags); * * \note Saving Impulse Tracker tags is not supported. */ bool save(); private: File(const File &); File &operator=(const File &); void read(bool readProperties); class FilePrivate; FilePrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/it/itproperties.cpp�������������������������������������������������������������0000664�0000000�0000000�00000012047�12225024651�0020102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright :(C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "itproperties.h" using namespace TagLib; using namespace IT; class IT::Properties::PropertiesPrivate { public: PropertiesPrivate() : channels(0), lengthInPatterns(0), instrumentCount(0), sampleCount(0), patternCount(0), version(0), compatibleVersion(0), flags(0), special(0), globalVolume(0), mixVolume(0), tempo(0), bpmSpeed(0), panningSeparation(0), pitchWheelDepth(0) { } int channels; ushort lengthInPatterns; ushort instrumentCount; ushort sampleCount; ushort patternCount; ushort version; ushort compatibleVersion; ushort flags; ushort special; uchar globalVolume; uchar mixVolume; uchar tempo; uchar bpmSpeed; uchar panningSeparation; uchar pitchWheelDepth; }; IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate) { } IT::Properties::~Properties() { delete d; } int IT::Properties::length() const { return 0; } int IT::Properties::bitrate() const { return 0; } int IT::Properties::sampleRate() const { return 0; } int IT::Properties::channels() const { return d->channels; } TagLib::ushort IT::Properties::lengthInPatterns() const { return d->lengthInPatterns; } bool IT::Properties::stereo() const { return d->flags & Stereo; } TagLib::ushort IT::Properties::instrumentCount() const { return d->instrumentCount; } TagLib::ushort IT::Properties::sampleCount() const { return d->sampleCount; } TagLib::ushort IT::Properties::patternCount() const { return d->patternCount; } TagLib::ushort IT::Properties::version() const { return d->version; } TagLib::ushort IT::Properties::compatibleVersion() const { return d->compatibleVersion; } TagLib::ushort IT::Properties::flags() const { return d->flags; } TagLib::ushort IT::Properties::special() const { return d->special; } uchar IT::Properties::globalVolume() const { return d->globalVolume; } uchar IT::Properties::mixVolume() const { return d->mixVolume; } uchar IT::Properties::tempo() const { return d->tempo; } uchar IT::Properties::bpmSpeed() const { return d->bpmSpeed; } uchar IT::Properties::panningSeparation() const { return d->panningSeparation; } uchar IT::Properties::pitchWheelDepth() const { return d->pitchWheelDepth; } void IT::Properties::setChannels(int channels) { d->channels = channels; } void IT::Properties::setLengthInPatterns(ushort lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } void IT::Properties::setInstrumentCount(ushort instrumentCount) { d->instrumentCount = instrumentCount; } void IT::Properties::setSampleCount(ushort sampleCount) { d->sampleCount = sampleCount; } void IT::Properties::setPatternCount(ushort patternCount) { d->patternCount = patternCount; } void IT::Properties::setFlags(ushort flags) { d->flags = flags; } void IT::Properties::setSpecial(ushort special) { d->special = special; } void IT::Properties::setCompatibleVersion(ushort compatibleVersion) { d->compatibleVersion = compatibleVersion; } void IT::Properties::setVersion(ushort version) { d->version = version; } void IT::Properties::setGlobalVolume(uchar globalVolume) { d->globalVolume = globalVolume; } void IT::Properties::setMixVolume(uchar mixVolume) { d->mixVolume = mixVolume; } void IT::Properties::setTempo(uchar tempo) { d->tempo = tempo; } void IT::Properties::setBpmSpeed(uchar bpmSpeed) { d->bpmSpeed = bpmSpeed; } void IT::Properties::setPanningSeparation(uchar panningSeparation) { d->panningSeparation = panningSeparation; } void IT::Properties::setPitchWheelDepth(uchar pitchWheelDepth) { d->pitchWheelDepth = pitchWheelDepth; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/it/itproperties.h���������������������������������������������������������������0000664�0000000�0000000�00000007426�12225024651�0017554�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_ITPROPERTIES_H #define TAGLIB_ITPROPERTIES_H #include "taglib.h" #include "audioproperties.h" namespace TagLib { namespace IT { class TAGLIB_EXPORT Properties : public AudioProperties { friend class File; public: /*! Flag bits. */ enum { Stereo = 1, Vol0MixOptimizations = 2, UseInstruments = 4, LinearSlides = 8, OldEffects = 16, LinkEffects = 32, UseMidiPitchController = 64, RequestEmbeddedMidiConf = 128 }; /*! Special bits. */ enum { MessageAttached = 1, MidiConfEmbedded = 8 }; Properties(AudioProperties::ReadStyle propertiesStyle); virtual ~Properties(); int length() const; int bitrate() const; int sampleRate() const; int channels() const; ushort lengthInPatterns() const; bool stereo() const; ushort instrumentCount() const; ushort sampleCount() const; ushort patternCount() const; ushort version() const; ushort compatibleVersion() const; ushort flags() const; ushort special() const; uchar globalVolume() const; uchar mixVolume() const; uchar tempo() const; uchar bpmSpeed() const; uchar panningSeparation() const; uchar pitchWheelDepth() const; void setChannels(int channels); void setLengthInPatterns(ushort lengthInPatterns); void setInstrumentCount(ushort instrumentCount); void setSampleCount (ushort sampleCount); void setPatternCount(ushort patternCount); void setVersion (ushort version); void setCompatibleVersion(ushort compatibleVersion); void setFlags (ushort flags); void setSpecial (ushort special); void setGlobalVolume(uchar globalVolume); void setMixVolume (uchar mixVolume); void setTempo (uchar tempo); void setBpmSpeed (uchar bpmSpeed); void setPanningSeparation(uchar panningSeparation); void setPitchWheelDepth (uchar pitchWheelDepth); private: Properties(const Properties&); Properties &operator=(const Properties&); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015004�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modfile.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000012370�12225024651�0017132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "modfile.h" #include "tstringlist.h" #include "tdebug.h" #include "modfileprivate.h" #include "tpropertymap.h" using namespace TagLib; using namespace Mod; class Mod::File::FilePrivate { public: FilePrivate(AudioProperties::ReadStyle propertiesStyle) : properties(propertiesStyle) { } Mod::Tag tag; Mod::Properties properties; }; Mod::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } Mod::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } Mod::File::~File() { delete d; } Mod::Tag *Mod::File::tag() const { return &d->tag; } Mod::Properties *Mod::File::audioProperties() const { return &d->properties; } PropertyMap Mod::File::properties() const { return d->tag.properties(); } PropertyMap Mod::File::setProperties(const PropertyMap &properties) { return d->tag.setProperties(properties); } bool Mod::File::save() { if(readOnly()) { debug("Mod::File::save() - Cannot save to a read only file."); return false; } seek(0); writeString(d->tag.title(), 20); StringList lines = d->tag.comment().split("\n"); uint n = std::min(lines.size(), d->properties.instrumentCount()); for(uint i = 0; i < n; ++ i) { writeString(lines[i], 22); seek(8, Current); } for(uint i = n; i < d->properties.instrumentCount(); ++ i) { writeString(String::null, 22); seek(8, Current); } return true; } void Mod::File::read(bool) { if(!isOpen()) return; seek(1080); ByteVector modId = readBlock(4); READ_ASSERT(modId.size() == 4); int channels = 4; uint instruments = 31; if(modId == "M.K." || modId == "M!K!" || modId == "M&K!" || modId == "N.T.") { d->tag.setTrackerName("ProTracker"); channels = 4; } else if(modId.startsWith("FLT") || modId.startsWith("TDZ")) { d->tag.setTrackerName("StarTrekker"); char digit = modId[3]; READ_ASSERT(digit >= '0' && digit <= '9'); channels = digit - '0'; } else if(modId.endsWith("CHN")) { d->tag.setTrackerName("StarTrekker"); char digit = modId[0]; READ_ASSERT(digit >= '0' && digit <= '9'); channels = digit - '0'; } else if(modId == "CD81" || modId == "OKTA") { d->tag.setTrackerName("Atari Oktalyzer"); channels = 8; } else if(modId.endsWith("CH") || modId.endsWith("CN")) { d->tag.setTrackerName("TakeTracker"); char digit = modId[0]; READ_ASSERT(digit >= '0' && digit <= '9'); channels = (digit - '0') * 10; digit = modId[1]; READ_ASSERT(digit >= '0' && digit <= '9'); channels += digit - '0'; } else { // Not sure if this is correct. I'd need a file // created with NoiseTracker to check this. d->tag.setTrackerName("NoiseTracker"); // probably channels = 4; instruments = 15; } d->properties.setChannels(channels); d->properties.setInstrumentCount(instruments); seek(0); READ_STRING(d->tag.setTitle, 20); StringList comment; for(uint i = 0; i < instruments; ++ i) { READ_STRING_AS(instrumentName, 22); // value in words, * 2 (<< 1) for bytes: READ_U16B_AS(sampleLength); READ_BYTE_AS(fineTuneByte); int fineTune = fineTuneByte & 0xF; // > 7 means negative value if(fineTune > 7) fineTune -= 16; READ_BYTE_AS(volume); if(volume > 64) volume = 64; // volume in decibels: 20 * log10(volume / 64) // value in words, * 2 (<< 1) for bytes: READ_U16B_AS(repeatStart); // value in words, * 2 (<< 1) for bytes: READ_U16B_AS(repatLength); comment.append(instrumentName); } READ_BYTE(d->properties.setLengthInPatterns); d->tag.setComment(comment.toString("\n")); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modfile.h�������������������������������������������������������������������0000664�0000000�0000000�00000007225�12225024651�0016602�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_MODFILE_H #define TAGLIB_MODFILE_H #include "tfile.h" #include "audioproperties.h" #include "taglib_export.h" #include "modfilebase.h" #include "modtag.h" #include "modproperties.h" namespace TagLib { namespace Mod { class TAGLIB_EXPORT File : public TagLib::Mod::FileBase { public: /*! * Constructs a Protracker file from \a file. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. */ File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Constructs a Protracker file from \a stream. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. */ File(IOStream *stream, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); Mod::Tag *tag() const; /*! * Implements the unified property interface -- export function. * Forwards to Mod::Tag::properties(). */ PropertyMap properties() const; /*! * Implements the unified property interface -- import function. * Forwards to Mod::Tag::setProperties(). */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the Mod::Properties for this file. If no audio properties * were read then this will return a null pointer. */ Mod::Properties *audioProperties() const; /*! * Save the file. * This is the same as calling save(AllTags); * * \note Saving Protracker tags is not supported. */ bool save(); private: File(const File &); File &operator=(const File &); void read(bool readProperties); class FilePrivate; FilePrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modfilebase.cpp�������������������������������������������������������������0000664�0000000�0000000�00000006524�12225024651�0017771�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "tdebug.h" #include "modfilebase.h" using namespace TagLib; using namespace Mod; Mod::FileBase::FileBase(FileName file) : TagLib::File(file) { } Mod::FileBase::FileBase(IOStream *stream) : TagLib::File(stream) { } void Mod::FileBase::writeString(const String &s, ulong size, char padding) { ByteVector data(s.data(String::Latin1)); data.resize(size, padding); writeBlock(data); } bool Mod::FileBase::readString(String &s, ulong size) { ByteVector data(readBlock(size)); if(data.size() < size) return false; int index = data.find((char) 0); if(index > -1) { data.resize(index); } data.replace((char) 0xff, ' '); s = data; return true; } void Mod::FileBase::writeByte(uchar byte) { ByteVector data(1, byte); writeBlock(data); } void Mod::FileBase::writeU16L(ushort number) { writeBlock(ByteVector::fromShort(number, false)); } void Mod::FileBase::writeU32L(ulong number) { writeBlock(ByteVector::fromUInt(number, false)); } void Mod::FileBase::writeU16B(ushort number) { writeBlock(ByteVector::fromShort(number, true)); } void Mod::FileBase::writeU32B(ulong number) { writeBlock(ByteVector::fromUInt(number, true)); } bool Mod::FileBase::readByte(uchar &byte) { ByteVector data(readBlock(1)); if(data.size() < 1) return false; byte = data[0]; return true; } bool Mod::FileBase::readU16L(ushort &number) { ByteVector data(readBlock(2)); if(data.size() < 2) return false; number = data.toUShort(false); return true; } bool Mod::FileBase::readU32L(ulong &number) { ByteVector data(readBlock(4)); if(data.size() < 4) return false; number = data.toUInt(false); return true; } bool Mod::FileBase::readU16B(ushort &number) { ByteVector data(readBlock(2)); if(data.size() < 2) return false; number = data.toUShort(true); return true; } bool Mod::FileBase::readU32B(ulong &number) { ByteVector data(readBlock(4)); if(data.size() < 4) return false; number = data.toUInt(true); return true; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modfilebase.h���������������������������������������������������������������0000664�0000000�0000000�00000004371�12225024651�0017434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_MODFILEBASE_H #define TAGLIB_MODFILEBASE_H #include "taglib.h" #include "tfile.h" #include "tstring.h" #include "tlist.h" #include "taglib_export.h" #include <algorithm> namespace TagLib { namespace Mod { class TAGLIB_EXPORT FileBase : public TagLib::File { protected: FileBase(FileName file); FileBase(IOStream *stream); void writeString(const String &s, ulong size, char padding = 0); void writeByte(uchar byte); void writeU16L(ushort number); void writeU32L(ulong number); void writeU16B(ushort number); void writeU32B(ulong number); bool readString(String &s, ulong size); bool readByte(uchar &byte); bool readU16L(ushort &number); bool readU32L(ulong &number); bool readU16B(ushort &number); bool readU32B(ulong &number); }; } } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modfileprivate.h������������������������������������������������������������0000664�0000000�0000000�00000005100�12225024651�0020163�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_MODFILEPRIVATE_H #define TAGLIB_MODFILEPRIVATE_H // some helper-macros only used internally by (s3m|it|xm)file.cpp #define READ_ASSERT(cond) \ if(!(cond)) \ { \ setValid(false); \ return; \ } #define READ(setter,type,read) \ { \ type number; \ READ_ASSERT(read(number)); \ setter(number); \ } #define READ_BYTE(setter) READ(setter,uchar,readByte) #define READ_U16L(setter) READ(setter,ushort,readU16L) #define READ_U32L(setter) READ(setter,ulong,readU32L) #define READ_U16B(setter) READ(setter,ushort,readU16B) #define READ_U32B(setter) READ(setter,ulong,readU32B) #define READ_STRING(setter,size) \ { \ String s; \ READ_ASSERT(readString(s, size)); \ setter(s); \ } #define READ_AS(type,name,read) \ type name = 0; \ READ_ASSERT(read(name)); #define READ_BYTE_AS(name) READ_AS(uchar,name,readByte) #define READ_U16L_AS(name) READ_AS(ushort,name,readU16L) #define READ_U32L_AS(name) READ_AS(ulong,name,readU32L) #define READ_U16B_AS(name) READ_AS(ushort,name,readU16B) #define READ_U32B_AS(name) READ_AS(ulong,name,readU32B) #define READ_STRING_AS(name,size) \ String name; \ READ_ASSERT(readString(name, size)); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modproperties.cpp�����������������������������������������������������������0000664�0000000�0000000�00000005064�12225024651�0020411�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "modproperties.h" using namespace TagLib; using namespace Mod; class Mod::Properties::PropertiesPrivate { public: PropertiesPrivate() : channels(0), instrumentCount(0), lengthInPatterns(0) { } int channels; uint instrumentCount; uchar lengthInPatterns; }; Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate) { } Mod::Properties::~Properties() { delete d; } int Mod::Properties::length() const { return 0; } int Mod::Properties::bitrate() const { return 0; } int Mod::Properties::sampleRate() const { return 0; } int Mod::Properties::channels() const { return d->channels; } TagLib::uint Mod::Properties::instrumentCount() const { return d->instrumentCount; } uchar Mod::Properties::lengthInPatterns() const { return d->lengthInPatterns; } void Mod::Properties::setChannels(int channels) { d->channels = channels; } void Mod::Properties::setInstrumentCount(uint instrumentCount) { d->instrumentCount = instrumentCount; } void Mod::Properties::setLengthInPatterns(uchar lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modproperties.h�������������������������������������������������������������0000664�0000000�0000000�00000004360�12225024651�0020054�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_MODPROPERTIES_H #define TAGLIB_MODPROPERTIES_H #include "taglib.h" #include "audioproperties.h" namespace TagLib { namespace Mod { class TAGLIB_EXPORT Properties : public AudioProperties { public: Properties(AudioProperties::ReadStyle propertiesStyle); virtual ~Properties(); int length() const; int bitrate() const; int sampleRate() const; int channels() const; uint instrumentCount() const; uchar lengthInPatterns() const; void setChannels(int channels); void setInstrumentCount(uint sampleCount); void setLengthInPatterns(uchar lengthInPatterns); private: friend class File; Properties(const Properties&); Properties &operator=(const Properties&); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modtag.cpp������������������������������������������������������������������0000664�0000000�0000000�00000007616�12225024651�0016775�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "modtag.h" #include "tstringlist.h" #include "tpropertymap.h" using namespace TagLib; using namespace Mod; class Mod::Tag::TagPrivate { public: TagPrivate() { } String title; String comment; String trackerName; }; Mod::Tag::Tag() : TagLib::Tag() { d = new TagPrivate; } Mod::Tag::~Tag() { delete d; } String Mod::Tag::title() const { return d->title; } String Mod::Tag::artist() const { return String::null; } String Mod::Tag::album() const { return String::null; } String Mod::Tag::comment() const { return d->comment; } String Mod::Tag::genre() const { return String::null; } TagLib::uint Mod::Tag::year() const { return 0; } TagLib::uint Mod::Tag::track() const { return 0; } String Mod::Tag::trackerName() const { return d->trackerName; } void Mod::Tag::setTitle(const String &title) { d->title = title; } void Mod::Tag::setArtist(const String &) { } void Mod::Tag::setAlbum(const String &) { } void Mod::Tag::setComment(const String &comment) { d->comment = comment; } void Mod::Tag::setGenre(const String &) { } void Mod::Tag::setYear(uint) { } void Mod::Tag::setTrack(uint) { } void Mod::Tag::setTrackerName(const String &trackerName) { d->trackerName = trackerName; } PropertyMap Mod::Tag::properties() const { PropertyMap properties; properties["TITLE"] = d->title; properties["COMMENT"] = d->comment; if(!(d->trackerName.isNull())) properties["TRACKERNAME"] = d->trackerName; return properties; } PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) { PropertyMap properties(origProps); properties.removeEmpty(); StringList oneValueSet; if(properties.contains("TITLE")) { d->title = properties["TITLE"].front(); oneValueSet.append("TITLE"); } else d->title = String::null; if(properties.contains("COMMENT")) { d->comment = properties["COMMENT"].front(); oneValueSet.append("COMMENT"); } else d->comment = String::null; if(properties.contains("TRACKERNAME")) { d->trackerName = properties["TRACKERNAME"].front(); oneValueSet.append("TRACKERNAME"); } else d->trackerName = String::null; // for each tag that has been set above, remove the first entry in the corresponding // value list. The others will be returned as unsupported by this format. for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) { if(properties[*it].size() == 1) properties.erase(*it); else properties[*it].erase( properties[*it].begin() ); } return properties; } ������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mod/modtag.h��������������������������������������������������������������������0000664�0000000�0000000�00000014754�12225024651�0016443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_MODTAG_H #define TAGLIB_MODTAG_H #include "tag.h" namespace TagLib { namespace Mod { /*! * Tags for module files (Mod, S3M, IT, XM). * * Note that only the \a title is supported as such by most * module file formats. Except for XM files the \a trackerName * is derived from the file format or the flavour of the file * format. For XM files it is stored in the file. * * The \a comment tag is not strictly supported by module files, * but it is common practice to abuse instrument/sample/pattern * names as multiline comments. TagLib does so as well. */ class TAGLIB_EXPORT Tag : public TagLib::Tag { public: Tag(); virtual ~Tag(); /*! * Returns the track name; if no track name is present in the tag * String::null will be returned. */ String title() const; /*! * Not supported by module files. Therefore always returns String::null. */ String artist() const; /*! * Not supported by module files. Therefore always returns String::null. */ String album() const; /*! * Returns the track comment derived from the instrument/sample/pattern * names; if no comment is present in the tag String::null will be * returned. */ String comment() const; /*! * Not supported by module files. Therefore always returns String::null. */ String genre() const; /*! * Not supported by module files. Therefore always returns 0. */ uint year() const; /*! * Not supported by module files. Therefore always returns 0. */ uint track() const; /*! * Returns the name of the tracker used to create/edit the module file. * Only XM files store this tag to the file as such, for other formats * (Mod, S3M, IT) this is derived from the file type or the flavour of * the file type. Therefore only XM files might have an empty * (String::null) tracker name. */ String trackerName() const; /*! * Sets the title to \a title. If \a title is String::null then this * value will be cleared. * * The length limits per file type are (1 characetr = 1 byte): * Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 * characters. */ void setTitle(const String &title); /*! * Not supported by module files and therefore ignored. */ void setArtist(const String &artist); /*! * Not supported by module files and therefore ignored. */ void setAlbum(const String &album); /*! * Sets the comment to \a comment. If \a comment is String::null then * this value will be cleared. * * Note that module file formats don't actually support a comment tag. * Instead the names of instruments/patterns/samples are abused as * a multiline comment. Because of this the number of lines in a * module file is fixed to the number of instruments/patterns/samples. * * Also note that the instrument/pattern/sample name length is limited * an thus the line length in comments are limited. Too big comments * will be truncated. * * The line length limits per file type are (1 characetr = 1 byte): * Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22 * characters. */ void setComment(const String &comment); /*! * Not supported by module files and therefore ignored. */ void setGenre(const String &genre); /*! * Not supported by module files and therefore ignored. */ void setYear(uint year); /*! * Not supported by module files and therefore ignored. */ void setTrack(uint track); /*! * Sets the tracker name to \a trackerName. If \a trackerName is * String::null then this value will be cleared. * * Note that only XM files support this tag. Setting the * tracker name for other module file formats will be ignored. * * The length of this tag is limited to 20 characters (1 character * = 1 byte). */ void setTrackerName(const String &trackerName); /*! * Implements the unified property interface -- export function. * Since the module tag is very limited, the exported map is as well. */ PropertyMap properties() const; /*! * Implements the unified property interface -- import function. * Because of the limitations of the module file tag, any tags besides * COMMENT, TITLE and, if it is an XM file, TRACKERNAME, will be * returened. Additionally, if the map contains tags with multiple values, * all but the first will be contained in the returned map of unsupported * properties. */ PropertyMap setProperties(const PropertyMap &); private: Tag(const Tag &); Tag &operator=(const Tag &); class TagPrivate; TagPrivate *d; }; } } #endif ��������������������taglib-1.9.1/taglib/mp4/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014725�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4atom.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000012537�12225024651�0017022�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tstring.h> #include "mp4atom.h" using namespace TagLib; const char *MP4::Atom::containers[11] = { "moov", "udta", "mdia", "meta", "ilst", "stbl", "minf", "moof", "traf", "trak", "stsd" }; MP4::Atom::Atom(File *file) { offset = file->tell(); ByteVector header = file->readBlock(8); if (header.size() != 8) { // The atom header must be 8 bytes long, otherwise there is either // trailing garbage or the file is truncated debug("MP4: Couldn't read 8 bytes of data for atom header"); length = 0; file->seek(0, File::End); return; } length = header.toUInt(); if (length == 1) { const long long longLength = file->readBlock(8).toLongLong(); if (longLength >= 8 && longLength <= 0xFFFFFFFF) { // The atom has a 64-bit length, but it's actually a 32-bit value length = (long)longLength; } else { debug("MP4: 64-bit atoms are not supported"); length = 0; file->seek(0, File::End); return; } } if (length < 8) { debug("MP4: Invalid atom size"); length = 0; file->seek(0, File::End); return; } name = header.mid(4, 4); for(int i = 0; i < numContainers; i++) { if(name == containers[i]) { if(name == "meta") { file->seek(4, File::Current); } else if(name == "stsd") { file->seek(8, File::Current); } while(file->tell() < offset + length) { MP4::Atom *child = new MP4::Atom(file); children.append(child); if (child->length == 0) return; } return; } } file->seek(offset + length); } MP4::Atom::~Atom() { for(unsigned int i = 0; i < children.size(); i++) { delete children[i]; } children.clear(); } MP4::Atom * MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4) { if(name1 == 0) { return this; } for(unsigned int i = 0; i < children.size(); i++) { if(children[i]->name == name1) { return children[i]->find(name2, name3, name4); } } return 0; } MP4::AtomList MP4::Atom::findall(const char *name, bool recursive) { MP4::AtomList result; for(unsigned int i = 0; i < children.size(); i++) { if(children[i]->name == name) { result.append(children[i]); } if(recursive) { result.append(children[i]->findall(name, recursive)); } } return result; } bool MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3) { path.append(this); if(name1 == 0) { return true; } for(unsigned int i = 0; i < children.size(); i++) { if(children[i]->name == name1) { return children[i]->path(path, name2, name3); } } return false; } MP4::Atoms::Atoms(File *file) { file->seek(0, File::End); long end = file->tell(); file->seek(0); while(file->tell() + 8 <= end) { MP4::Atom *atom = new MP4::Atom(file); atoms.append(atom); if (atom->length == 0) break; } } MP4::Atoms::~Atoms() { for(unsigned int i = 0; i < atoms.size(); i++) { delete atoms[i]; } atoms.clear(); } MP4::Atom * MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4) { for(unsigned int i = 0; i < atoms.size(); i++) { if(atoms[i]->name == name1) { return atoms[i]->find(name2, name3, name4); } } return 0; } MP4::AtomList MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4) { MP4::AtomList path; for(unsigned int i = 0; i < atoms.size(); i++) { if(atoms[i]->name == name1) { if(!atoms[i]->path(path, name2, name3, name4)) { path.clear(); } return path; } } return path; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4atom.h�������������������������������������������������������������������0000664�0000000�0000000�00000011142�12225024651�0016456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007,2011 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ // This file is not part of the public API! #ifndef DO_NOT_DOCUMENT #ifndef TAGLIB_MP4ATOM_H #define TAGLIB_MP4ATOM_H #include "tfile.h" #include "tlist.h" namespace TagLib { namespace MP4 { class Atom; typedef TagLib::List<Atom *> AtomList; enum AtomDataType { TypeImplicit = 0, // for use with tags for which no type needs to be indicated because only one type is allowed TypeUTF8 = 1, // without any count or null terminator TypeUTF16 = 2, // also known as UTF-16BE TypeSJIS = 3, // deprecated unless it is needed for special Japanese characters TypeHTML = 6, // the HTML file header specifies which HTML version TypeXML = 7, // the XML header must identify the DTD or schemas TypeUUID = 8, // also known as GUID; stored as 16 bytes in binary (valid as an ID) TypeISRC = 9, // stored as UTF-8 text (valid as an ID) TypeMI3P = 10, // stored as UTF-8 text (valid as an ID) TypeGIF = 12, // (deprecated) a GIF image TypeJPEG = 13, // a JPEG image TypePNG = 14, // a PNG image TypeURL = 15, // absolute, in UTF-8 characters TypeDuration = 16, // in milliseconds, 32-bit integer TypeDateTime = 17, // in UTC, counting seconds since midnight, January 1, 1904; 32 or 64-bits TypeGenred = 18, // a list of enumerated values TypeInteger = 21, // a signed big-endian integer with length one of { 1,2,3,4,8 } bytes TypeRIAAPA = 24, // RIAA parental advisory; { -1=no, 1=yes, 0=unspecified }, 8-bit ingteger TypeUPC = 25, // Universal Product Code, in text UTF-8 format (valid as an ID) TypeBMP = 27, // Windows bitmap image TypeUndefined = 255 // undefined }; struct AtomData { AtomData(AtomDataType type, ByteVector data) : type(type), locale(0), data(data) {} AtomDataType type; int locale; ByteVector data; }; typedef TagLib::List<AtomData> AtomDataList; class Atom { public: Atom(File *file); ~Atom(); Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0); AtomList findall(const char *name, bool recursive = false); long offset; long length; TagLib::ByteVector name; AtomList children; private: static const int numContainers = 11; static const char *containers[11]; }; //! Root-level atoms class Atoms { public: Atoms(File *file); ~Atoms(); Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); AtomList atoms; }; } } #endif #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4coverart.cpp�������������������������������������������������������������0000664�0000000�0000000�00000005022�12225024651�0017676�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2009 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <taglib.h> #include <tdebug.h> #include "trefcounter.h" #include "mp4coverart.h" using namespace TagLib; class MP4::CoverArt::CoverArtPrivate : public RefCounter { public: CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {} Format format; ByteVector data; }; MP4::CoverArt::CoverArt(Format format, const ByteVector &data) { d = new CoverArtPrivate; d->format = format; d->data = data; } MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d) { d->ref(); } MP4::CoverArt & MP4::CoverArt::operator=(const CoverArt &item) { if(d->deref()) { delete d; } d = item.d; d->ref(); return *this; } MP4::CoverArt::~CoverArt() { if(d->deref()) { delete d; } } MP4::CoverArt::Format MP4::CoverArt::format() const { return d->format; } ByteVector MP4::CoverArt::data() const { return d->data; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4coverart.h���������������������������������������������������������������0000664�0000000�0000000�00000005060�12225024651�0017345�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2009 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MP4COVERART_H #define TAGLIB_MP4COVERART_H #include "tlist.h" #include "tbytevector.h" #include "taglib_export.h" #include "mp4atom.h" namespace TagLib { namespace MP4 { class TAGLIB_EXPORT CoverArt { public: /*! * This describes the image type. */ enum Format { JPEG = TypeJPEG, PNG = TypePNG, BMP = TypeBMP, GIF = TypeGIF, Unknown = TypeImplicit, }; CoverArt(Format format, const ByteVector &data); ~CoverArt(); CoverArt(const CoverArt &item); CoverArt &operator=(const CoverArt &item); //! Format of the image Format format() const; //! The image data ByteVector data() const; private: class CoverArtPrivate; CoverArtPrivate *d; }; typedef List<CoverArt> CoverArtList; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4file.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000010163�12225024651�0016772�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tstring.h> #include <tpropertymap.h> #include "mp4atom.h" #include "mp4tag.h" #include "mp4file.h" using namespace TagLib; class MP4::File::FilePrivate { public: FilePrivate() : tag(0), atoms(0), properties(0) { } ~FilePrivate() { if(atoms) { delete atoms; atoms = 0; } if(tag) { delete tag; tag = 0; } if(properties) { delete properties; properties = 0; } } MP4::Tag *tag; MP4::Atoms *atoms; MP4::Properties *properties; }; MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, audioPropertiesStyle); } MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle) : TagLib::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, audioPropertiesStyle); } MP4::File::~File() { delete d; } MP4::Tag * MP4::File::tag() const { return d->tag; } PropertyMap MP4::File::properties() const { return d->tag->properties(); } void MP4::File::removeUnsupportedProperties(const StringList &properties) { d->tag->removeUnsupportedProperties(properties); } PropertyMap MP4::File::setProperties(const PropertyMap &properties) { return d->tag->setProperties(properties); } MP4::Properties * MP4::File::audioProperties() const { return d->properties; } bool MP4::File::checkValid(const MP4::AtomList &list) { for(uint i = 0; i < list.size(); i++) { if(list[i]->length == 0) return false; if(!checkValid(list[i]->children)) return false; } return true; } void MP4::File::read(bool readProperties, Properties::ReadStyle audioPropertiesStyle) { if(!isValid()) return; d->atoms = new Atoms(this); if (!checkValid(d->atoms->atoms)) { setValid(false); return; } // must have a moov atom, otherwise consider it invalid MP4::Atom *moov = d->atoms->find("moov"); if(!moov) { setValid(false); return; } d->tag = new Tag(this, d->atoms); if(readProperties) { d->properties = new Properties(this, d->atoms, audioPropertiesStyle); } } bool MP4::File::save() { if(readOnly()) { debug("MP4::File::save() -- File is read only."); return false; } if(!isValid()) { debug("MP4::File::save() -- Trying to save invalid file."); return false; } return d->tag->save(); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4file.h�������������������������������������������������������������������0000664�0000000�0000000�00000011134�12225024651�0016436�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MP4FILE_H #define TAGLIB_MP4FILE_H #include "tag.h" #include "tfile.h" #include "taglib_export.h" #include "mp4properties.h" #include "mp4tag.h" namespace TagLib { //! An implementation of MP4 (AAC, ALAC, ...) metadata namespace MP4 { class Atoms; /*! * This implements and provides an interface for MP4 files to the * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * the abstract TagLib::File API as well as providing some additional * information specific to MP4 files. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * Constructs an MP4 file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average); /*! * Constructs an MP4 file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); /*! * Returns a pointer to the MP4 tag of the file. * * MP4::Tag implements the tag interface, so this serves as the * reimplementation of TagLib::File::tag(). * * \note The Tag <b>is still</b> owned by the MP4::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. */ Tag *tag() const; /*! * Implements the unified property interface -- export function. */ PropertyMap properties() const; /*! * Removes unsupported properties. Forwards to the actual Tag's * removeUnsupportedProperties() function. */ void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the MP4 audio properties for this file. */ Properties *audioProperties() const; /*! * Save the file. * * This returns true if the save was successful. */ bool save(); private: void read(bool readProperties, Properties::ReadStyle audioPropertiesStyle); bool checkValid(const MP4::AtomList &list); class FilePrivate; FilePrivate *d; }; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4item.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000010224�12225024651�0017007�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <taglib.h> #include <tdebug.h> #include "trefcounter.h" #include "mp4item.h" using namespace TagLib; class MP4::Item::ItemPrivate : public RefCounter { public: ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {} bool valid; AtomDataType atomDataType; union { bool m_bool; int m_int; IntPair m_intPair; uchar m_byte; uint m_uint; long long m_longlong; }; StringList m_stringList; ByteVectorList m_byteVectorList; MP4::CoverArtList m_coverArtList; }; MP4::Item::Item() { d = new ItemPrivate; d->valid = false; } MP4::Item::Item(const Item &item) : d(item.d) { d->ref(); } MP4::Item & MP4::Item::operator=(const Item &item) { if(d->deref()) { delete d; } d = item.d; d->ref(); return *this; } MP4::Item::~Item() { if(d->deref()) { delete d; } } MP4::Item::Item(bool value) { d = new ItemPrivate; d->m_bool = value; } MP4::Item::Item(int value) { d = new ItemPrivate; d->m_int = value; } MP4::Item::Item(uchar value) { d = new ItemPrivate; d->m_byte = value; } MP4::Item::Item(uint value) { d = new ItemPrivate; d->m_uint = value; } MP4::Item::Item(long long value) { d = new ItemPrivate; d->m_longlong = value; } MP4::Item::Item(int value1, int value2) { d = new ItemPrivate; d->m_intPair.first = value1; d->m_intPair.second = value2; } MP4::Item::Item(const ByteVectorList &value) { d = new ItemPrivate; d->m_byteVectorList = value; } MP4::Item::Item(const StringList &value) { d = new ItemPrivate; d->m_stringList = value; } MP4::Item::Item(const MP4::CoverArtList &value) { d = new ItemPrivate; d->m_coverArtList = value; } void MP4::Item::setAtomDataType(MP4::AtomDataType type) { d->atomDataType = type; } MP4::AtomDataType MP4::Item::atomDataType() const { return d->atomDataType; } bool MP4::Item::toBool() const { return d->m_bool; } int MP4::Item::toInt() const { return d->m_int; } uchar MP4::Item::toByte() const { return d->m_byte; } TagLib::uint MP4::Item::toUInt() const { return d->m_uint; } long long MP4::Item::toLongLong() const { return d->m_longlong; } MP4::Item::IntPair MP4::Item::toIntPair() const { return d->m_intPair; } StringList MP4::Item::toStringList() const { return d->m_stringList; } ByteVectorList MP4::Item::toByteVectorList() const { return d->m_byteVectorList; } MP4::CoverArtList MP4::Item::toCoverArtList() const { return d->m_coverArtList; } bool MP4::Item::isValid() const { return d->valid; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4item.h�������������������������������������������������������������������0000664�0000000�0000000�00000005503�12225024651�0016460�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MP4ITEM_H #define TAGLIB_MP4ITEM_H #include "tstringlist.h" #include "mp4coverart.h" #include "taglib_export.h" namespace TagLib { namespace MP4 { class TAGLIB_EXPORT Item { public: struct IntPair { int first, second; }; Item(); Item(const Item &item); Item &operator=(const Item &item); ~Item(); Item(int value); Item(uchar value); Item(uint value); Item(long long value); Item(bool value); Item(int first, int second); Item(const StringList &value); Item(const ByteVectorList &value); Item(const CoverArtList &value); void setAtomDataType(AtomDataType type); AtomDataType atomDataType() const; int toInt() const; uchar toByte() const; uint toUInt() const; long long toLongLong() const; bool toBool() const; IntPair toIntPair() const; StringList toStringList() const; ByteVectorList toByteVectorList() const; CoverArtList toCoverArtList() const; bool isValid() const; private: class ItemPrivate; ItemPrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4properties.cpp�����������������������������������������������������������0000664�0000000�0000000�00000012430�12225024651�0020246�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tstring.h> #include "mp4file.h" #include "mp4atom.h" #include "mp4properties.h" using namespace TagLib; class MP4::Properties::PropertiesPrivate { public: PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0), encrypted(false), codec(MP4::Properties::Unknown) {} int length; int bitrate; int sampleRate; int channels; int bitsPerSample; bool encrypted; Codec codec; }; MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate; MP4::Atom *moov = atoms->find("moov"); if(!moov) { debug("MP4: Atom 'moov' not found"); return; } MP4::Atom *trak = 0; ByteVector data; MP4::AtomList trakList = moov->findall("trak"); for (unsigned int i = 0; i < trakList.size(); i++) { trak = trakList[i]; MP4::Atom *hdlr = trak->find("mdia", "hdlr"); if(!hdlr) { debug("MP4: Atom 'trak.mdia.hdlr' not found"); return; } file->seek(hdlr->offset); data = file->readBlock(hdlr->length); if(data.mid(16, 4) == "soun") { break; } trak = 0; } if (!trak) { debug("MP4: No audio tracks"); return; } MP4::Atom *mdhd = trak->find("mdia", "mdhd"); if(!mdhd) { debug("MP4: Atom 'trak.mdia.mdhd' not found"); return; } file->seek(mdhd->offset); data = file->readBlock(mdhd->length); uint version = data[8]; if(version == 1) { if (data.size() < 36 + 8) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } const long long unit = data.toLongLong(28U); const long long length = data.toLongLong(36U); d->length = unit ? int(length / unit) : 0; } else { if (data.size() < 24 + 4) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } const unsigned int unit = data.toUInt(20U); const unsigned int length = data.toUInt(24U); d->length = unit ? length / unit : 0; } MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd"); if(!atom) { return; } file->seek(atom->offset); data = file->readBlock(atom->length); if(data.mid(20, 4) == "mp4a") { d->codec = AAC; d->channels = data.toShort(40U); d->bitsPerSample = data.toShort(42U); d->sampleRate = data.toUInt(46U); if(data.mid(56, 4) == "esds" && data[64] == 0x03) { uint pos = 65; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } pos += 4; if(data[pos] == 0x04) { pos += 1; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } pos += 10; d->bitrate = (data.toUInt(pos) + 500) / 1000; } } } else if (data.mid(20, 4) == "alac") { if (atom->length == 88 && data.mid(56, 4) == "alac") { d->codec = ALAC; d->bitsPerSample = data.at(69); d->channels = data.at(73); d->bitrate = data.toUInt(80U) / 1000; d->sampleRate = data.toUInt(84U); } } MP4::Atom *drms = atom->find("drms"); if(drms) { d->encrypted = true; } } MP4::Properties::~Properties() { delete d; } int MP4::Properties::channels() const { return d->channels; } int MP4::Properties::sampleRate() const { return d->sampleRate; } int MP4::Properties::length() const { return d->length; } int MP4::Properties::bitrate() const { return d->bitrate; } int MP4::Properties::bitsPerSample() const { return d->bitsPerSample; } bool MP4::Properties::isEncrypted() const { return d->encrypted; } MP4::Properties::Codec MP4::Properties::codec() const { return d->codec; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4properties.h�������������������������������������������������������������0000664�0000000�0000000�00000005053�12225024651�0017716�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MP4PROPERTIES_H #define TAGLIB_MP4PROPERTIES_H #include "taglib_export.h" #include "audioproperties.h" namespace TagLib { namespace MP4 { class Atoms; class File; //! An implementation of MP4 audio properties class TAGLIB_EXPORT Properties : public AudioProperties { public: enum Codec { Unknown = 0, AAC, ALAC }; Properties(File *file, Atoms *atoms, ReadStyle style = Average); virtual ~Properties(); virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; virtual int bitsPerSample() const; bool isEncrypted() const; //! Audio codec used in the MP4 file Codec codec() const; private: class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mp4/mp4tag.cpp������������������������������������������������������������������0000664�0000000�0000000�00000062723�12225024651�0016637�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007,2011 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tstring.h> #include <tpropertymap.h> #include "mp4atom.h" #include "mp4tag.h" #include "id3v1genres.h" using namespace TagLib; class MP4::Tag::TagPrivate { public: TagPrivate() : file(0), atoms(0) {} ~TagPrivate() {} TagLib::File *file; Atoms *atoms; ItemListMap items; }; MP4::Tag::Tag() { d = new TagPrivate; } MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) { d = new TagPrivate; d->file = file; d->atoms = atoms; MP4::Atom *ilst = atoms->find("moov", "udta", "meta", "ilst"); if(!ilst) { //debug("Atom moov.udta.meta.ilst not found."); return; } for(unsigned int i = 0; i < ilst->children.size(); i++) { MP4::Atom *atom = ilst->children[i]; file->seek(atom->offset + 8); if(atom->name == "----") { parseFreeForm(atom, file); } else if(atom->name == "trkn" || atom->name == "disk") { parseIntPair(atom, file); } else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" || atom->name == "hdvd") { parseBool(atom, file); } else if(atom->name == "tmpo") { parseInt(atom, file); } else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" || atom->name == "sfID" || atom->name == "atID" || atom->name == "geID") { parseUInt(atom, file); } else if(atom->name == "plID") { parseLongLong(atom, file); } else if(atom->name == "stik" || atom->name == "rtng" || atom->name == "akID") { parseByte(atom, file); } else if(atom->name == "gnre") { parseGnre(atom, file); } else if(atom->name == "covr") { parseCovr(atom, file); } else { parseText(atom, file); } } } MP4::Tag::~Tag() { delete d; } MP4::AtomDataList MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm) { AtomDataList result; ByteVector data = file->readBlock(atom->length - 8); int i = 0; unsigned int pos = 0; while(pos < data.size()) { const int length = static_cast<int>(data.toUInt(pos)); ByteVector name = data.mid(pos + 4, 4); const int flags = static_cast<int>(data.toUInt(pos + 8)); if(freeForm && i < 2) { if(i == 0 && name != "mean") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\""); return result; } else if(i == 1 && name != "name") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\""); return result; } result.append(AtomData(AtomDataType(flags), data.mid(pos + 12, length - 12))); } else { if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); return result; } if(expectedFlags == -1 || flags == expectedFlags) { result.append(AtomData(AtomDataType(flags), data.mid(pos + 16, length - 16))); } } pos += length; i++; } return result; } ByteVectorList MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm) { AtomDataList data = parseData2(atom, file, expectedFlags, freeForm); ByteVectorList result; for(uint i = 0; i < data.size(); i++) { result.append(data[i].data); } return result; } void MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { addItem(atom->name, (int)data[0].toShort()); } } void MP4::Tag::parseUInt(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { addItem(atom->name, data[0].toUInt()); } } void MP4::Tag::parseLongLong(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { addItem(atom->name, data[0].toLongLong()); } } void MP4::Tag::parseByte(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { addItem(atom->name, (uchar)data[0].at(0)); } } void MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { int idx = (int)data[0].toShort(); if(idx > 0) { addItem("\251gen", StringList(ID3v1::genre(idx - 1))); } } } void MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { const int a = data[0].toShort(2U); const int b = data[0].toShort(4U); addItem(atom->name, MP4::Item(a, b)); } } void MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file) { ByteVectorList data = parseData(atom, file); if(data.size()) { bool value = data[0].size() ? data[0][0] != '\0' : false; addItem(atom->name, value); } } void MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags) { ByteVectorList data = parseData(atom, file, expectedFlags); if(data.size()) { StringList value; for(unsigned int i = 0; i < data.size(); i++) { value.append(String(data[i], String::UTF8)); } addItem(atom->name, value); } } void MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file) { AtomDataList data = parseData2(atom, file, -1, true); if(data.size() > 2) { String name = "----:" + String(data[0].data, String::UTF8) + ':' + String(data[1].data, String::UTF8); AtomDataType type = data[2].type; for(uint i = 2; i < data.size(); i++) { if(data[i].type != type) { debug("MP4: We currently don't support values with multiple types"); break; } } if(type == TypeUTF8) { StringList value; for(uint i = 2; i < data.size(); i++) { value.append(String(data[i].data, String::UTF8)); } Item item(value); item.setAtomDataType(type); addItem(name, item); } else { ByteVectorList value; for(uint i = 2; i < data.size(); i++) { value.append(data[i].data); } Item item(value); item.setAtomDataType(type); addItem(name, item); } } } void MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file) { MP4::CoverArtList value; ByteVector data = file->readBlock(atom->length - 8); unsigned int pos = 0; while(pos < data.size()) { const int length = static_cast<int>(data.toUInt(pos)); ByteVector name = data.mid(pos + 4, 4); const int flags = static_cast<int>(data.toUInt(pos + 8)); if(name != "data") { debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); break; } if(flags == TypeJPEG || flags == TypePNG || flags == TypeBMP || flags == TypeGIF || flags == TypeImplicit) { value.append(MP4::CoverArt(MP4::CoverArt::Format(flags), data.mid(pos + 16, length - 16))); } else { debug("MP4: Unknown covr format " + String::number(flags)); } pos += length; } if(value.size() > 0) addItem(atom->name, value); } ByteVector MP4::Tag::padIlst(const ByteVector &data, int length) { if (length == -1) { length = ((data.size() + 1023) & ~1023) - data.size(); } return renderAtom("free", ByteVector(length, '\1')); } ByteVector MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) { return ByteVector::fromUInt(data.size() + 8) + name + data; } ByteVector MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) { ByteVector result; for(unsigned int i = 0; i < data.size(); i++) { result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + data[i])); } return renderAtom(name, result); } ByteVector MP4::Tag::renderBool(const ByteVector &name, MP4::Item &item) { ByteVectorList data; data.append(ByteVector(1, item.toBool() ? '\1' : '\0')); return renderData(name, TypeInteger, data); } ByteVector MP4::Tag::renderInt(const ByteVector &name, MP4::Item &item) { ByteVectorList data; data.append(ByteVector::fromShort(item.toInt())); return renderData(name, TypeInteger, data); } ByteVector MP4::Tag::renderUInt(const ByteVector &name, MP4::Item &item) { ByteVectorList data; data.append(ByteVector::fromUInt(item.toUInt())); return renderData(name, TypeInteger, data); } ByteVector MP4::Tag::renderLongLong(const ByteVector &name, MP4::Item &item) { ByteVectorList data; data.append(ByteVector::fromLongLong(item.toLongLong())); return renderData(name, TypeInteger, data); } ByteVector MP4::Tag::renderByte(const ByteVector &name, MP4::Item &item) { ByteVectorList data; data.append(ByteVector(1, item.toByte())); return renderData(name, TypeInteger, data); } ByteVector MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item) { ByteVectorList data; data.append(ByteVector(2, '\0') + ByteVector::fromShort(item.toIntPair().first) + ByteVector::fromShort(item.toIntPair().second) + ByteVector(2, '\0')); return renderData(name, TypeImplicit, data); } ByteVector MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, MP4::Item &item) { ByteVectorList data; data.append(ByteVector(2, '\0') + ByteVector::fromShort(item.toIntPair().first) + ByteVector::fromShort(item.toIntPair().second)); return renderData(name, TypeImplicit, data); } ByteVector MP4::Tag::renderText(const ByteVector &name, MP4::Item &item, int flags) { ByteVectorList data; StringList value = item.toStringList(); for(unsigned int i = 0; i < value.size(); i++) { data.append(value[i].data(String::UTF8)); } return renderData(name, flags, data); } ByteVector MP4::Tag::renderCovr(const ByteVector &name, MP4::Item &item) { ByteVector data; MP4::CoverArtList value = item.toCoverArtList(); for(unsigned int i = 0; i < value.size(); i++) { data.append(renderAtom("data", ByteVector::fromUInt(value[i].format()) + ByteVector(4, '\0') + value[i].data())); } return renderAtom(name, data); } ByteVector MP4::Tag::renderFreeForm(const String &name, MP4::Item &item) { StringList header = StringList::split(name, ":"); if (header.size() != 3) { debug("MP4: Invalid free-form item name \"" + name + "\""); return ByteVector::null; } ByteVector data; data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8))); data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8))); AtomDataType type = item.atomDataType(); if(type == TypeUndefined) { if(!item.toStringList().isEmpty()) { type = TypeUTF8; } else { type = TypeImplicit; } } if(type == TypeUTF8) { StringList value = item.toStringList(); for(unsigned int i = 0; i < value.size(); i++) { data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i].data(String::UTF8))); } } else { ByteVectorList value = item.toByteVectorList(); for(unsigned int i = 0; i < value.size(); i++) { data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i])); } } return renderAtom("----", data); } bool MP4::Tag::save() { ByteVector data; for(MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) { const String name = i->first; if(name.startsWith("----")) { data.append(renderFreeForm(name, i->second)); } else if(name == "trkn") { data.append(renderIntPair(name.data(String::Latin1), i->second)); } else if(name == "disk") { data.append(renderIntPairNoTrailing(name.data(String::Latin1), i->second)); } else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") { data.append(renderBool(name.data(String::Latin1), i->second)); } else if(name == "tmpo") { data.append(renderInt(name.data(String::Latin1), i->second)); } else if(name == "tvsn" || name == "tves" || name == "cnID" || name == "sfID" || name == "atID" || name == "geID") { data.append(renderUInt(name.data(String::Latin1), i->second)); } else if(name == "plID") { data.append(renderLongLong(name.data(String::Latin1), i->second)); } else if(name == "stik" || name == "rtng" || name == "akID") { data.append(renderByte(name.data(String::Latin1), i->second)); } else if(name == "covr") { data.append(renderCovr(name.data(String::Latin1), i->second)); } else if(name.size() == 4){ data.append(renderText(name.data(String::Latin1), i->second)); } else { debug("MP4: Unknown item name \"" + name + "\""); } } data = renderAtom("ilst", data); AtomList path = d->atoms->path("moov", "udta", "meta", "ilst"); if(path.size() == 4) { saveExisting(data, path); } else { saveNew(data); } return true; } void MP4::Tag::updateParents(AtomList &path, long delta, int ignore) { for(unsigned int i = 0; i < path.size() - ignore; i++) { d->file->seek(path[i]->offset); long size = d->file->readBlock(4).toUInt(); // 64-bit if (size == 1) { d->file->seek(4, File::Current); // Skip name long long longSize = d->file->readBlock(8).toLongLong(); // Seek the offset of the 64-bit size d->file->seek(path[i]->offset + 8); d->file->writeBlock(ByteVector::fromLongLong(longSize + delta)); } // 32-bit else { d->file->seek(path[i]->offset); d->file->writeBlock(ByteVector::fromUInt(size + delta)); } } } void MP4::Tag::updateOffsets(long delta, long offset) { MP4::Atom *moov = d->atoms->find("moov"); if(moov) { MP4::AtomList stco = moov->findall("stco", true); for(unsigned int i = 0; i < stco.size(); i++) { MP4::Atom *atom = stco[i]; if(atom->offset > offset) { atom->offset += delta; } d->file->seek(atom->offset + 12); ByteVector data = d->file->readBlock(atom->length - 12); unsigned int count = data.toUInt(); d->file->seek(atom->offset + 16); uint pos = 4; while(count--) { long o = static_cast<long>(data.toUInt(pos)); if(o > offset) { o += delta; } d->file->writeBlock(ByteVector::fromUInt(o)); pos += 4; } } MP4::AtomList co64 = moov->findall("co64", true); for(unsigned int i = 0; i < co64.size(); i++) { MP4::Atom *atom = co64[i]; if(atom->offset > offset) { atom->offset += delta; } d->file->seek(atom->offset + 12); ByteVector data = d->file->readBlock(atom->length - 12); unsigned int count = data.toUInt(); d->file->seek(atom->offset + 16); uint pos = 4; while(count--) { long long o = data.toLongLong(pos); if(o > offset) { o += delta; } d->file->writeBlock(ByteVector::fromLongLong(o)); pos += 8; } } } MP4::Atom *moof = d->atoms->find("moof"); if(moof) { MP4::AtomList tfhd = moof->findall("tfhd", true); for(unsigned int i = 0; i < tfhd.size(); i++) { MP4::Atom *atom = tfhd[i]; if(atom->offset > offset) { atom->offset += delta; } d->file->seek(atom->offset + 9); ByteVector data = d->file->readBlock(atom->length - 9); const unsigned int flags = data.toUInt(0, 3, true); if(flags & 1) { long long o = data.toLongLong(7U); if(o > offset) { o += delta; } d->file->seek(atom->offset + 16); d->file->writeBlock(ByteVector::fromLongLong(o)); } } } } void MP4::Tag::saveNew(ByteVector &data) { data = renderAtom("meta", TagLib::ByteVector(4, '\0') + renderAtom("hdlr", TagLib::ByteVector(8, '\0') + TagLib::ByteVector("mdirappl") + TagLib::ByteVector(9, '\0')) + data + padIlst(data)); AtomList path = d->atoms->path("moov", "udta"); if(path.size() != 2) { path = d->atoms->path("moov"); data = renderAtom("udta", data); } long offset = path[path.size() - 1]->offset + 8; d->file->insert(data, offset, 0); updateParents(path, data.size()); updateOffsets(data.size(), offset); } void MP4::Tag::saveExisting(ByteVector &data, AtomList &path) { MP4::Atom *ilst = path[path.size() - 1]; long offset = ilst->offset; long length = ilst->length; MP4::Atom *meta = path[path.size() - 2]; AtomList::Iterator index = meta->children.find(ilst); // check if there is an atom before 'ilst', and possibly use it as padding if(index != meta->children.begin()) { AtomList::Iterator prevIndex = index; prevIndex--; MP4::Atom *prev = *prevIndex; if(prev->name == "free") { offset = prev->offset; length += prev->length; } } // check if there is an atom after 'ilst', and possibly use it as padding AtomList::Iterator nextIndex = index; nextIndex++; if(nextIndex != meta->children.end()) { MP4::Atom *next = *nextIndex; if(next->name == "free") { length += next->length; } } long delta = data.size() - length; if(delta > 0 || (delta < 0 && delta > -8)) { data.append(padIlst(data)); delta = data.size() - length; } else if(delta < 0) { data.append(padIlst(data, -delta - 8)); delta = 0; } d->file->insert(data, offset, length); if(delta) { updateParents(path, delta, 1); updateOffsets(delta, offset); } } String MP4::Tag::title() const { if(d->items.contains("\251nam")) return d->items["\251nam"].toStringList().toString(", "); return String::null; } String MP4::Tag::artist() const { if(d->items.contains("\251ART")) return d->items["\251ART"].toStringList().toString(", "); return String::null; } String MP4::Tag::album() const { if(d->items.contains("\251alb")) return d->items["\251alb"].toStringList().toString(", "); return String::null; } String MP4::Tag::comment() const { if(d->items.contains("\251cmt")) return d->items["\251cmt"].toStringList().toString(", "); return String::null; } String MP4::Tag::genre() const { if(d->items.contains("\251gen")) return d->items["\251gen"].toStringList().toString(", "); return String::null; } unsigned int MP4::Tag::year() const { if(d->items.contains("\251day")) return d->items["\251day"].toStringList().toString().toInt(); return 0; } unsigned int MP4::Tag::track() const { if(d->items.contains("trkn")) return d->items["trkn"].toIntPair().first; return 0; } void MP4::Tag::setTitle(const String &value) { d->items["\251nam"] = StringList(value); } void MP4::Tag::setArtist(const String &value) { d->items["\251ART"] = StringList(value); } void MP4::Tag::setAlbum(const String &value) { d->items["\251alb"] = StringList(value); } void MP4::Tag::setComment(const String &value) { d->items["\251cmt"] = StringList(value); } void MP4::Tag::setGenre(const String &value) { d->items["\251gen"] = StringList(value); } void MP4::Tag::setYear(uint value) { d->items["\251day"] = StringList(String::number(value)); } void MP4::Tag::setTrack(uint value) { d->items["trkn"] = MP4::Item(value, 0); } MP4::ItemListMap & MP4::Tag::itemListMap() { return d->items; } static const char *keyTranslation[][2] = { { "\251nam", "TITLE" }, { "\251ART", "ARTIST" }, { "\251alb", "ALBUM" }, { "\251cmt", "COMMENT" }, { "\251gen", "GENRE" }, { "\251day", "DATE" }, { "\251wrt", "COMPOSER" }, { "\251grp", "GROUPING" }, { "trkn", "TRACKNUMBER" }, { "disk", "DISCNUMBER" }, { "cpil", "COMPILATION" }, { "tmpo", "BPM" }, { "cprt", "COPYRIGHT" }, { "\251lyr", "LYRICS" }, { "\251too", "ENCODEDBY" }, { "soal", "ALBUMSORT" }, { "soaa", "ALBUMARTISTSORT" }, { "soar", "ARTISTSORT" }, { "sonm", "TITLESORT" }, { "soco", "COMPOSERSORT" }, { "sosn", "SHOWSORT" }, { "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" }, { "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, { "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, { "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, { "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, { "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, { "----:com.apple.iTunes:ASIN", "ASIN" }, { "----:com.apple.iTunes:LABEL", "LABEL" }, { "----:com.apple.iTunes:LYRICIST", "LYRICIST" }, { "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" }, { "----:com.apple.iTunes:REMIXER", "REMIXER" }, { "----:com.apple.iTunes:ENGINEER", "ENGINEER" }, { "----:com.apple.iTunes:PRODUCER", "PRODUCER" }, { "----:com.apple.iTunes:DJMIXER", "DJMIXER" }, { "----:com.apple.iTunes:MIXER", "MIXER" }, { "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" }, { "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" }, { "----:com.apple.iTunes:MOOD", "MOOD" }, { "----:com.apple.iTunes:ISRC", "ISRC" }, { "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" }, { "----:com.apple.iTunes:BARCODE", "BARCODE" }, { "----:com.apple.iTunes:SCRIPT", "SCRIPT" }, { "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" }, { "----:com.apple.iTunes:LICENSE", "LICENSE" }, { "----:com.apple.iTunes:MEDIA", "MEDIA" }, }; PropertyMap MP4::Tag::properties() const { static Map<String, String> keyMap; if(keyMap.isEmpty()) { int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); for(int i = 0; i < numKeys; i++) { keyMap[keyTranslation[i][0]] = keyTranslation[i][1]; } } PropertyMap props; MP4::ItemListMap::ConstIterator it = d->items.begin(); for(; it != d->items.end(); ++it) { if(keyMap.contains(it->first)) { String key = keyMap[it->first]; if(key == "TRACKNUMBER" || key == "DISCNUMBER") { MP4::Item::IntPair ip = it->second.toIntPair(); String value = String::number(ip.first); if(ip.second) { value += "/" + String::number(ip.second); } props[key] = value; } else if(key == "BPM") { props[key] = String::number(it->second.toInt()); } else if(key == "COMPILATION") { props[key] = String::number(it->second.toBool()); } else { props[key] = it->second.toStringList(); } } else { props.unsupportedData().append(it->first); } } return props; } void MP4::Tag::removeUnsupportedProperties(const StringList &props) { StringList::ConstIterator it = props.begin(); for(; it != props.end(); ++it) d->items.erase(*it); } PropertyMap MP4::Tag::setProperties(const PropertyMap &props) { static Map<String, String> reverseKeyMap; if(reverseKeyMap.isEmpty()) { int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]); for(int i = 0; i < numKeys; i++) { reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0]; } } PropertyMap origProps = properties(); PropertyMap::ConstIterator it = origProps.begin(); for(; it != origProps.end(); ++it) { if(!props.contains(it->first) || props[it->first].isEmpty()) { d->items.erase(reverseKeyMap[it->first]); } } PropertyMap ignoredProps; it = props.begin(); for(; it != props.end(); ++it) { if(reverseKeyMap.contains(it->first)) { String name = reverseKeyMap[it->first]; if(it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") { int first = 0, second = 0; StringList parts = StringList::split(it->second.front(), "/"); if(parts.size() > 0) { first = parts[0].toInt(); if(parts.size() > 1) { second = parts[1].toInt(); } d->items[name] = MP4::Item(first, second); } } else if(it->first == "BPM") { int value = it->second.front().toInt(); d->items[name] = MP4::Item(value); } else if(it->first == "COMPILATION") { bool value = (it->second.front().toInt() != 0); d->items[name] = MP4::Item(value); } else { d->items[name] = it->second; } } else { ignoredProps.insert(it->first, it->second); } } return ignoredProps; } void MP4::Tag::addItem(const String &name, const Item &value) { if(!d->items.contains(name)) { d->items.insert(name, value); } else { debug("MP4: Ignoring duplicate atom \"" + name + "\""); } } ���������������������������������������������taglib-1.9.1/taglib/mp4/mp4tag.h��������������������������������������������������������������������0000664�0000000�0000000�00000012145�12225024651�0016275�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** copyright : (C) 2007,2011 by Lukáš Lalinský email : lalinsky@gmail.com **************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MP4TAG_H #define TAGLIB_MP4TAG_H #include "tag.h" #include "tbytevectorlist.h" #include "tfile.h" #include "tmap.h" #include "tstringlist.h" #include "taglib_export.h" #include "mp4atom.h" #include "mp4item.h" namespace TagLib { namespace MP4 { typedef TagLib::Map<String, Item> ItemListMap; class TAGLIB_EXPORT Tag: public TagLib::Tag { public: Tag(); Tag(TagLib::File *file, Atoms *atoms); ~Tag(); bool save(); String title() const; String artist() const; String album() const; String comment() const; String genre() const; uint year() const; uint track() const; void setTitle(const String &value); void setArtist(const String &value); void setAlbum(const String &value); void setComment(const String &value); void setGenre(const String &value); void setYear(uint value); void setTrack(uint value); ItemListMap &itemListMap(); PropertyMap properties() const; void removeUnsupportedProperties(const StringList& properties); PropertyMap setProperties(const PropertyMap &properties); private: AtomDataList parseData2(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false); TagLib::ByteVectorList parseData(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false); void parseText(Atom *atom, TagLib::File *file, int expectedFlags = 1); void parseFreeForm(Atom *atom, TagLib::File *file); void parseInt(Atom *atom, TagLib::File *file); void parseByte(Atom *atom, TagLib::File *file); void parseUInt(Atom *atom, TagLib::File *file); void parseLongLong(Atom *atom, TagLib::File *file); void parseGnre(Atom *atom, TagLib::File *file); void parseIntPair(Atom *atom, TagLib::File *file); void parseBool(Atom *atom, TagLib::File *file); void parseCovr(Atom *atom, TagLib::File *file); TagLib::ByteVector padIlst(const ByteVector &data, int length = -1); TagLib::ByteVector renderAtom(const ByteVector &name, const TagLib::ByteVector &data); TagLib::ByteVector renderData(const ByteVector &name, int flags, const TagLib::ByteVectorList &data); TagLib::ByteVector renderText(const ByteVector &name, Item &item, int flags = TypeUTF8); TagLib::ByteVector renderFreeForm(const String &name, Item &item); TagLib::ByteVector renderBool(const ByteVector &name, Item &item); TagLib::ByteVector renderInt(const ByteVector &name, Item &item); TagLib::ByteVector renderByte(const ByteVector &name, Item &item); TagLib::ByteVector renderUInt(const ByteVector &name, Item &item); TagLib::ByteVector renderLongLong(const ByteVector &name, Item &item); TagLib::ByteVector renderIntPair(const ByteVector &name, Item &item); TagLib::ByteVector renderIntPairNoTrailing(const ByteVector &name, Item &item); TagLib::ByteVector renderCovr(const ByteVector &name, Item &item); void updateParents(AtomList &path, long delta, int ignore = 0); void updateOffsets(long delta, long offset); void saveNew(TagLib::ByteVector &data); void saveExisting(TagLib::ByteVector &data, AtomList &path); void addItem(const String &name, const Item &value); class TagPrivate; TagPrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpc/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015004�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpc/mpcfile.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000020727�12225024651�0017137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tstring.h> #include <tagunion.h> #include <tdebug.h> #include <tpropertymap.h> #include "mpcfile.h" #include "id3v1tag.h" #include "id3v2header.h" #include "apetag.h" #include "apefooter.h" using namespace TagLib; namespace { enum { MPCAPEIndex = 0, MPCID3v1Index = 1 }; } class MPC::File::FilePrivate { public: FilePrivate() : APELocation(-1), APESize(0), ID3v1Location(-1), ID3v2Header(0), ID3v2Location(-1), ID3v2Size(0), properties(0), scanned(false), hasAPE(false), hasID3v1(false), hasID3v2(false) {} ~FilePrivate() { delete ID3v2Header; delete properties; } long APELocation; uint APESize; long ID3v1Location; ID3v2::Header *ID3v2Header; long ID3v2Location; uint ID3v2Size; TagUnion tag; Properties *properties; bool scanned; // These indicate whether the file *on disk* has these tags, not if // this data structure does. This is used in computing offsets. bool hasAPE; bool hasID3v1; bool hasID3v2; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } MPC::File::~File() { delete d; } TagLib::Tag *MPC::File::tag() const { return &d->tag; } PropertyMap MPC::File::properties() const { if(d->hasAPE) return d->tag.access<APE::Tag>(MPCAPEIndex, false)->properties(); if(d->hasID3v1) return d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->properties(); return PropertyMap(); } void MPC::File::removeUnsupportedProperties(const StringList &properties) { if(d->hasAPE) d->tag.access<APE::Tag>(MPCAPEIndex, false)->removeUnsupportedProperties(properties); if(d->hasID3v1) d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->removeUnsupportedProperties(properties); } PropertyMap MPC::File::setProperties(const PropertyMap &properties) { if(d->hasID3v1) d->tag.access<APE::Tag>(MPCID3v1Index, false)->setProperties(properties); return d->tag.access<APE::Tag>(MPCAPEIndex, true)->setProperties(properties); } MPC::Properties *MPC::File::audioProperties() const { return d->properties; } bool MPC::File::save() { if(readOnly()) { debug("MPC::File::save() -- File is read only."); return false; } // Possibly strip ID3v2 tag if(d->hasID3v2 && !d->ID3v2Header) { removeBlock(d->ID3v2Location, d->ID3v2Size); d->hasID3v2 = false; if(d->hasID3v1) d->ID3v1Location -= d->ID3v2Size; if(d->hasAPE) d->APELocation -= d->ID3v2Size; } // Update ID3v1 tag if(ID3v1Tag()) { if(d->hasID3v1) { seek(d->ID3v1Location); writeBlock(ID3v1Tag()->render()); } else { seek(0, End); d->ID3v1Location = tell(); writeBlock(ID3v1Tag()->render()); d->hasID3v1 = true; } } else if(d->hasID3v1) { removeBlock(d->ID3v1Location, 128); d->hasID3v1 = false; if(d->hasAPE) { if(d->APELocation > d->ID3v1Location) d->APELocation -= 128; } } // Update APE tag if(APETag()) { if(d->hasAPE) insert(APETag()->render(), d->APELocation, d->APESize); else { if(d->hasID3v1) { insert(APETag()->render(), d->ID3v1Location, 0); d->APESize = APETag()->footer()->completeTagSize(); d->hasAPE = true; d->APELocation = d->ID3v1Location; d->ID3v1Location += d->APESize; } else { seek(0, End); d->APELocation = tell(); writeBlock(APETag()->render()); d->APESize = APETag()->footer()->completeTagSize(); d->hasAPE = true; } } } else if(d->hasAPE) { removeBlock(d->APELocation, d->APESize); d->hasAPE = false; if(d->hasID3v1) { if(d->ID3v1Location > d->APELocation) d->ID3v1Location -= d->APESize; } } return true; } ID3v1::Tag *MPC::File::ID3v1Tag(bool create) { return d->tag.access<ID3v1::Tag>(MPCID3v1Index, create); } APE::Tag *MPC::File::APETag(bool create) { return d->tag.access<APE::Tag>(MPCAPEIndex, create); } void MPC::File::strip(int tags) { if(tags & ID3v1) { d->tag.set(MPCID3v1Index, 0); APETag(true); } if(tags & ID3v2) { delete d->ID3v2Header; d->ID3v2Header = 0; } if(tags & APE) { d->tag.set(MPCAPEIndex, 0); if(!ID3v1Tag()) APETag(true); } } void MPC::File::remove(int tags) { strip(tags); } bool MPC::File::hasID3v1Tag() const { return d->hasID3v1; } bool MPC::File::hasAPETag() const { return d->hasAPE; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) { // Look for an ID3v1 tag d->ID3v1Location = findID3v1(); if(d->ID3v1Location >= 0) { d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); d->hasID3v1 = true; } // Look for an APE tag findAPE(); d->APELocation = findAPE(); if(d->APELocation >= 0) { d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation)); d->APESize = APETag()->footer()->completeTagSize(); d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; d->hasAPE = true; } if(!d->hasID3v1) APETag(true); // Look for and skip an ID3v2 tag d->ID3v2Location = findID3v2(); if(d->ID3v2Location >= 0) { seek(d->ID3v2Location); d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); d->ID3v2Size = d->ID3v2Header->completeTagSize(); d->hasID3v2 = true; } if(d->hasID3v2) seek(d->ID3v2Location + d->ID3v2Size); else seek(0); // Look for MPC metadata if(readProperties) { d->properties = new Properties(this, 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; } �����������������������������������������taglib-1.9.1/taglib/mpc/mpcfile.h�������������������������������������������������������������������0000664�0000000�0000000�00000017650�12225024651�0016605�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MPCFILE_H #define TAGLIB_MPCFILE_H #include "taglib_export.h" #include "tfile.h" #include "tag.h" #include "mpcproperties.h" #include "tlist.h" namespace TagLib { class Tag; namespace ID3v1 { class Tag; } namespace APE { class Tag; } //! An implementation of MPC metadata /*! * This is implementation of MPC metadata. * * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream * properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped * and ignored. */ namespace MPC { //! An implementation of TagLib::File with MPC specific methods /*! * This implements and provides an interface for MPC files to the * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing * the abstract TagLib::File API as well as providing some additional * information specific to MPC files. * The only invalid tag combination supported is an ID3v1 tag after an APE tag. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * This set of flags is used for various operations and is suitable for * being OR-ed together. */ enum TagTypes { //! Empty set. Matches no tag types. NoTags = 0x0000, //! Matches ID3v1 tags. ID3v1 = 0x0001, //! Matches ID3v2 tags. ID3v2 = 0x0002, //! Matches APE tags. APE = 0x0004, //! Matches all tag types. AllTags = 0xffff }; /*! * Constructs an MPC file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an MPC file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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; /*! * Implements the unified property interface -- export function. * If the file contains both an APE and an ID3v1 tag, only the APE * tag will be converted to the PropertyMap. */ PropertyMap properties() const; void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. * Affects only the APEv2 tag which will be created if necessary. * If an ID3v1 tag exists, it will be updated as well. */ PropertyMap setProperties(const PropertyMap &); /*! * 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 returns 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file * on disk actually has an ID3v1 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v1Tag() */ ID3v1::Tag *ID3v1Tag(bool create = false); /*! * Returns a pointer to the APE tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. If * there already be an ID3v1 tag, the new APE tag will be placed before it. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an APE tag. Use hasAPETag() to check if the file * on disk actually has an APE tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasAPETag() */ APE::Tag *APETag(bool create = false); /*! * This will remove the tags that match the OR-ed together TagTypes from the * file. By default it removes all tags. * * \warning This will also invalidate pointers to the tags * as their memory will be freed. * * \note In order to make the removal permanent save() still needs to be called. */ void strip(int tags = AllTags); /*! * \deprecated * \see strip */ void remove(int tags = AllTags); /*! * Returns whether or not the file on disk actually has an ID3v1 tag. * * \see ID3v1Tag() */ bool hasID3v1Tag() const; /*! * Returns whether or not the file on disk actually has an APE tag. * * \see APETag() */ bool hasAPETag() const; 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 ����������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpc/mpcproperties.cpp�����������������������������������������������������������0000664�0000000�0000000�00000020742�12225024651�0020411�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include <bitset> #include <math.h> #include "mpcproperties.h" #include "mpcfile.h" using namespace TagLib; class MPC::Properties::PropertiesPrivate { public: PropertiesPrivate(long length, ReadStyle s) : streamLength(length), style(s), version(0), length(0), bitrate(0), sampleRate(0), channels(0), totalFrames(0), sampleFrames(0), trackGain(0), trackPeak(0), albumGain(0), albumPeak(0) {} long streamLength; ReadStyle style; int version; int length; int bitrate; int sampleRate; int channels; uint totalFrames; uint sampleFrames; uint trackGain; uint trackPeak; uint albumGain; uint albumPeak; String flags; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(streamLength, style); readSV7(data); } MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(streamLength, style); ByteVector magic = file->readBlock(4); if(magic == "MPCK") { // Musepack version 8 readSV8(file); } else { // Musepack version 7 or older, fixed size header readSV7(magic + file->readBlock(MPC::HeaderSize - 4)); } } MPC::Properties::~Properties() { delete d; } int MPC::Properties::length() const { return d->length; } int MPC::Properties::bitrate() const { return d->bitrate; } int MPC::Properties::sampleRate() const { return d->sampleRate; } int MPC::Properties::channels() const { return d->channels; } int MPC::Properties::mpcVersion() const { return d->version; } TagLib::uint MPC::Properties::totalFrames() const { return d->totalFrames; } TagLib::uint MPC::Properties::sampleFrames() const { return d->sampleFrames; } int MPC::Properties::trackGain() const { return d->trackGain; } int MPC::Properties::trackPeak() const { return d->trackPeak; } int MPC::Properties::albumGain() const { return d->albumGain; } int MPC::Properties::albumPeak() const { return d->albumPeak; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// unsigned long readSize(File *file, TagLib::uint &sizelength) { unsigned char tmp; unsigned long size = 0; do { ByteVector b = file->readBlock(1); tmp = b[0]; size = (size << 7) | (tmp & 0x7F); sizelength++; } while((tmp & 0x80)); return size; } unsigned long readSize(const ByteVector &data, TagLib::uint &sizelength) { unsigned char tmp; unsigned long size = 0; unsigned long pos = 0; do { tmp = data[pos++]; size = (size << 7) | (tmp & 0x7F); sizelength++; } while((tmp & 0x80) && (pos < data.size())); return size; } static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 }; void MPC::Properties::readSV8(File *file) { bool readSH = false, readRG = false; while(!readSH && !readRG) { ByteVector packetType = file->readBlock(2); uint packetSizeLength = 0; unsigned long packetSize = readSize(file, packetSizeLength); unsigned long dataSize = packetSize - 2 - packetSizeLength; if(packetType == "SH") { // Stream Header // http://trac.musepack.net/wiki/SV8Specification#StreamHeaderPacket ByteVector data = file->readBlock(dataSize); readSH = true; TagLib::uint pos = 4; d->version = data[pos]; pos += 1; d->sampleFrames = readSize(data.mid(pos), pos); ulong begSilence = readSize(data.mid(pos), pos); std::bitset<16> flags(TAGLIB_CONSTRUCT_BITSET(data.toUShort(pos, true))); pos += 2; d->sampleRate = sftable[flags[15] * 4 + flags[14] * 2 + flags[13]]; d->channels = flags[7] * 8 + flags[6] * 4 + flags[5] * 2 + flags[4] + 1; if((d->sampleFrames - begSilence) != 0) d->bitrate = (int)(d->streamLength * 8.0 * d->sampleRate / (d->sampleFrames - begSilence)); d->bitrate = d->bitrate / 1000; d->length = (d->sampleFrames - begSilence) / d->sampleRate; } else if (packetType == "RG") { // Replay Gain // http://trac.musepack.net/wiki/SV8Specification#ReplaygainPacket ByteVector data = file->readBlock(dataSize); readRG = true; int replayGainVersion = data[0]; if(replayGainVersion == 1) { d->trackGain = data.toShort(1, true); d->trackPeak = data.toShort(3, true); d->albumGain = data.toShort(5, true); d->albumPeak = data.toShort(7, true); } } else if(packetType == "SE") { break; } else { file->seek(dataSize, File::Current); } } } void MPC::Properties::readSV7(const ByteVector &data) { if(data.startsWith("MP+")) { d->version = data[3] & 15; if(d->version < 7) return; d->totalFrames = data.toUInt(4, false); std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(8, false))); d->sampleRate = sftable[flags[17] * 2 + flags[16]]; d->channels = 2; uint gapless = data.toUInt(5, false); d->trackGain = data.toShort(14, false); d->trackPeak = data.toShort(12, false); d->albumGain = data.toShort(18, false); d->albumPeak = data.toShort(16, false); // convert gain info if(d->trackGain != 0) { int tmp = (int)((64.82 - (short)d->trackGain / 100.) * 256. + .5); if(tmp >= (1 << 16) || tmp < 0) tmp = 0; d->trackGain = tmp; } if(d->albumGain != 0) { int tmp = (int)((64.82 - d->albumGain / 100.) * 256. + .5); if(tmp >= (1 << 16) || tmp < 0) tmp = 0; d->albumGain = tmp; } if (d->trackPeak != 0) d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5); if (d->albumPeak != 0) d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5); bool trueGapless = (gapless >> 31) & 0x0001; if(trueGapless) { uint lastFrameSamples = (gapless >> 20) & 0x07FF; d->sampleFrames = d->totalFrames * 1152 - lastFrameSamples; } else d->sampleFrames = d->totalFrames * 1152 - 576; } else { uint headerData = data.toUInt(0, false); d->bitrate = (headerData >> 23) & 0x01ff; d->version = (headerData >> 11) & 0x03ff; d->sampleRate = 44100; d->channels = 2; if(d->version >= 5) d->totalFrames = data.toUInt(4, false); else d->totalFrames = data.toUShort(6, false); d->sampleFrames = d->totalFrames * 1152 - 576; } d->length = d->sampleRate > 0 ? (d->sampleFrames + (d->sampleRate / 2)) / d->sampleRate : 0; if(!d->bitrate) d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; } ������������������������������taglib-1.9.1/taglib/mpc/mpcproperties.h�������������������������������������������������������������0000664�0000000�0000000�00000010175�12225024651�0020055�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MPCPROPERTIES_H #define TAGLIB_MPCPROPERTIES_H #include "taglib_export.h" #include "audioproperties.h" namespace TagLib { namespace MPC { class File; static const uint HeaderSize = 8*7; //! An implementation of audio property reading for MPC /*! * This reads the data from an MPC stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of MPC::Properties with the data read from the * ByteVector \a data. * * This constructor is deprecated. It only works for MPC version up to 7. */ Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); /*! * Create an instance of MPC::Properties with the data read directly * from a MPC::File. */ Properties(File *file, 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-SV8) */ int mpcVersion() const; uint totalFrames() const; uint sampleFrames() const; /*! * Returns the track gain as an integer value, * to convert to dB: trackGain in dB = 64.82 - (trackGain / 256) */ int trackGain() const; /*! * Returns the track peak as an integer value, * to convert to dB: trackPeak in dB = trackPeak / 256 * to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768 */ int trackPeak() const; /*! * Returns the album gain as an integer value, * to convert to dB: albumGain in dB = 64.82 - (albumGain / 256) */ int albumGain() const; /*! * Returns the album peak as an integer value, * to convert to dB: albumPeak in dB = albumPeak / 256 * to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768 */ int albumPeak() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void readSV7(const ByteVector &data); void readSV8(File *file); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015155�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v1/���������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0016103�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v1/id3v1genres.cpp������������������������������������������������������0000664�0000000�0000000�00000012052�12225024651�0020741�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "id3v1genres.h" using namespace TagLib; namespace TagLib { namespace ID3v1 { static const int genresSize = 148; static const String genres[] = { "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop", "Synthpop" }; } } StringList ID3v1::genreList() { static StringList l; if(l.isEmpty()) { for(int i = 0; i < genresSize; i++) l.append(genres[i]); } return l; } ID3v1::GenreMap ID3v1::genreMap() { static GenreMap m; if(m.isEmpty()) { for(int i = 0; i < genresSize; i++) m.insert(genres[i], i); } return m; } String ID3v1::genre(int i) { if(i >= 0 && i < genresSize) return genres[i] + String::null; // always make a copy return String::null; } int ID3v1::genreIndex(const String &name) { if(genreMap().contains(name)) return genreMap()[name]; return 255; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v1/id3v1genres.h��������������������������������������������������������0000664�0000000�0000000�00000005376�12225024651�0020421�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V1GENRE_H #define TAGLIB_ID3V1GENRE_H #include "tmap.h" #include "tstringlist.h" #include "taglib_export.h" namespace TagLib { namespace ID3v1 { typedef Map<String, int> GenreMap; /*! * Returns the list of canonical ID3v1 genre names in the order that they * are listed in the standard. */ StringList TAGLIB_EXPORT genreList(); /*! * A "reverse mapping" that goes from the canonical ID3v1 genre name to the * respective genre number. genreMap()["Rock"] == */ GenreMap TAGLIB_EXPORT genreMap(); /*! * Returns the name of the genre at \a index in the ID3v1 genre list. If * \a index is out of range -- less than zero or greater than 146 -- a null * string will be returned. */ String TAGLIB_EXPORT genre(int index); /*! * Returns the genre index for the (case sensitive) genre \a name. If the * genre is not in the list 255 (which signifies an unknown genre in ID3v1) * will be returned. */ int TAGLIB_EXPORT genreIndex(const String &name); } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v1/id3v1tag.cpp���������������������������������������������������������0000664�0000000�0000000�00000015134�12225024651�0020235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tfile.h> #include "id3v1tag.h" #include "id3v1genres.h" using namespace TagLib; using namespace ID3v1; class ID3v1::Tag::TagPrivate { public: TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {} File *file; long tagOffset; String title; String artist; String album; String year; String comment; uchar track; uchar genre; static const StringHandler *stringHandler; }; static const StringHandler defaultStringHandler; const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler; //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// StringHandler::StringHandler() { } String ID3v1::StringHandler::parse(const ByteVector &data) const { return String(data, String::Latin1).stripWhiteSpace(); } ByteVector ID3v1::StringHandler::render(const String &s) const { if(!s.isLatin1()) { return ByteVector(); } return s.data(String::Latin1); } //////////////////////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////////////////////// ID3v1::Tag::Tag() : TagLib::Tag() { d = new TagPrivate; } ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag() { d = new TagPrivate; d->file = file; d->tagOffset = tagOffset; read(); } ID3v1::Tag::~Tag() { delete d; } ByteVector ID3v1::Tag::render() const { ByteVector data; data.append(fileIdentifier()); data.append(TagPrivate::stringHandler->render(d->title).resize(30)); data.append(TagPrivate::stringHandler->render(d->artist).resize(30)); data.append(TagPrivate::stringHandler->render(d->album).resize(30)); data.append(TagPrivate::stringHandler->render(d->year).resize(4)); data.append(TagPrivate::stringHandler->render(d->comment).resize(28)); data.append(char(0)); data.append(char(d->track)); data.append(char(d->genre)); return data; } ByteVector ID3v1::Tag::fileIdentifier() { return ByteVector::fromCString("TAG"); } String ID3v1::Tag::title() const { return d->title; } String ID3v1::Tag::artist() const { return d->artist; } String ID3v1::Tag::album() const { return d->album; } String ID3v1::Tag::comment() const { return d->comment; } String ID3v1::Tag::genre() const { return ID3v1::genre(d->genre); } TagLib::uint ID3v1::Tag::year() const { return d->year.toInt(); } TagLib::uint ID3v1::Tag::track() const { return d->track; } void ID3v1::Tag::setTitle(const String &s) { d->title = s; } void ID3v1::Tag::setArtist(const String &s) { d->artist = s; } void ID3v1::Tag::setAlbum(const String &s) { d->album = s; } void ID3v1::Tag::setComment(const String &s) { d->comment = s; } void ID3v1::Tag::setGenre(const String &s) { d->genre = ID3v1::genreIndex(s); } void ID3v1::Tag::setYear(TagLib::uint i) { d->year = i > 0 ? String::number(i) : String::null; } void ID3v1::Tag::setTrack(TagLib::uint i) { d->track = i < 256 ? i : 0; } TagLib::uint ID3v1::Tag::genreNumber() const { return d->genre; } void ID3v1::Tag::setGenreNumber(TagLib::uint i) { d->genre = i < 256 ? i : 255; } void ID3v1::Tag::setStringHandler(const StringHandler *handler) { if (handler) TagPrivate::stringHandler = handler; else TagPrivate::stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// // protected methods //////////////////////////////////////////////////////////////////////////////// void ID3v1::Tag::read() { if(d->file && d->file->isValid()) { d->file->seek(d->tagOffset); // read the tag -- always 128 bytes ByteVector data = d->file->readBlock(128); // some initial sanity checking if(data.size() == 128 && data.startsWith("TAG")) parse(data); else debug("ID3v1 tag is not valid or could not be read at the specified offset."); } } void ID3v1::Tag::parse(const ByteVector &data) { int offset = 3; d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30)); offset += 30; d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30)); offset += 30; d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30)); offset += 30; d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4)); offset += 4; // Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this // is not a bug in TagLib. Since a zeroed byte is what we would expect to // indicate the end of a C-String, specifically the comment string, a value of // zero must be assumed to be just that. if(data[offset + 28] == 0 && data[offset + 29] != 0) { // ID3v1.1 detected d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28)); d->track = uchar(data[offset + 29]); } else d->comment = data.mid(offset, 30); offset += 30; d->genre = uchar(data[offset]); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v1/id3v1tag.h�����������������������������������������������������������0000664�0000000�0000000�00000015654�12225024651�0017711�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V1TAG_H #define TAGLIB_ID3V1TAG_H #include "tag.h" #include "tbytevector.h" #include "taglib_export.h" namespace TagLib { class File; //! An ID3v1 implementation namespace ID3v1 { //! A abstraction for the string to data encoding in ID3v1 tags. /*! * ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In * practice it does not. TagLib by default only supports ISO-8859-1 data * in ID3v1 tags. * * However by subclassing this class and reimplementing parse() and render() * and setting your reimplementation as the default with * ID3v1::Tag::setStringHandler() you can define how you would like these * transformations to be done. * * \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1 * tags. Please consider disabling the writing of ID3v1 tags in the case * that the data is not ISO-8859-1. * * \see ID3v1::Tag::setStringHandler() */ class TAGLIB_EXPORT StringHandler { TAGLIB_IGNORE_MISSING_DESTRUCTOR public: // BIC: Add virtual destructor. StringHandler(); /*! * Decode a string from \a data. The default implementation assumes that * \a data is an ISO-8859-1 (Latin1) character array. */ virtual String parse(const ByteVector &data) const; /*! * Encode a ByteVector with the data from \a s. The default implementation * assumes that \a s is an ISO-8859-1 (Latin1) string. If the string is * does not conform to ISO-8859-1, no value is written. * * \warning It is recommended that you <b>not</b> override this method, but * instead do not write an ID3v1 tag in the case that the data is not * ISO-8859-1. */ virtual ByteVector render(const String &s) const; }; //! The main class in the ID3v1 implementation /*! * This is an implementation of the ID3v1 format. ID3v1 is both the simplist * and most common of tag formats but is rather limited. Because of its * pervasiveness and the way that applications have been written around the * fields that it provides, the generic TagLib::Tag API is a mirror of what is * provided by ID3v1. * * ID3v1 tags should generally only contain Latin1 information. However because * many applications do not follow this rule there is now support for overriding * the ID3v1 string handling using the ID3v1::StringHandler class. Please see * the documentation for that class for more information. * * \see StringHandler * * \note Most fields are truncated to a maximum of 28-30 bytes. The * truncation happens automatically when the tag is rendered. */ class TAGLIB_EXPORT Tag : public TagLib::Tag { public: /*! * Create an ID3v1 tag with default values. */ Tag(); /*! * Create an ID3v1 tag and parse the data in \a file starting at * \a tagOffset. */ Tag(File *file, long tagOffset); /*! * Destroys this Tag instance. */ virtual ~Tag(); /*! * Renders the in memory values to a ByteVector suitable for writing to * the file. */ ByteVector render() const; /*! * Returns the string "TAG" suitable for usage in locating the tag in a * file. */ static ByteVector fileIdentifier(); // Reimplementations. virtual String title() const; virtual String artist() const; virtual String album() const; virtual String comment() const; virtual String genre() const; virtual TagLib::uint year() const; virtual TagLib::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(TagLib::uint i); virtual void setTrack(TagLib::uint i); /*! * Returns the genre in number. * * /note Normally 255 indicates that this tag contains no genre. */ TagLib::uint genreNumber() const; /*! * Sets the genre in number to \a i. * * /note Valid value is from 0 up to 255. Normally 255 indicates that * this tag contains no genre. */ void setGenreNumber(TagLib::uint i); /*! * Sets the string handler that decides how the ID3v1 data will be * converted to and from binary data. * If the parameter \a handler is null, the previous handler is * released and default ISO-8859-1 handler is restored. * * \note The caller is responsible for deleting the previous handler * as needed after it is released. * * \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 ������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/���������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0016104�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/��������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0017361�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp��������������������������������������0000664�0000000�0000000�00000014573�12225024651�0024263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "attachedpictureframe.h" #include <tstringlist.h> #include <tdebug.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) { d = new AttachedPictureFramePrivate; setData(data); } 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; } String AttachedPictureFrame::description() const { return d->description; } void AttachedPictureFrame::setDescription(const String &desc) { d->description = desc; } 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; } d->textEncoding = String::Type(data[0]); int pos = 1; d->mimeType = readStringField(data, String::Latin1, &pos); /* Now we need at least two more bytes available */ if (uint(pos) + 1 >= data.size()) { debug("Truncated picture frame."); return; } d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++]; d->description = readStringField(data, d->textEncoding, &pos); d->data = data.mid(pos); } ByteVector AttachedPictureFrame::renderFields() const { ByteVector data; String::Type encoding = checkTextEncoding(d->description, d->textEncoding); data.append(char(encoding)); data.append(d->mimeType.data(String::Latin1)); data.append(textDelimiter(String::Latin1)); data.append(char(d->type)); data.append(d->description.data(encoding)); data.append(textDelimiter(encoding)); data.append(d->data); return data; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h) { d = new AttachedPictureFramePrivate; parseFields(fieldData(data)); } //////////////////////////////////////////////////////////////////////////////// // support for ID3v2.2 PIC frames //////////////////////////////////////////////////////////////////////////////// void AttachedPictureFrameV22::parseFields(const ByteVector &data) { if(data.size() < 5) { debug("A picture frame must contain at least 5 bytes."); return; } d->textEncoding = String::Type(data[0]); int pos = 1; String fixedString = String(data.mid(pos, 3), String::Latin1); pos += 3; // convert fixed string image type to mime string if (fixedString.upper() == "JPG") { d->mimeType = "image/jpeg"; } else if (fixedString.upper() == "PNG") { d->mimeType = "image/png"; } else { debug("probably unsupported image type"); d->mimeType = "image/" + fixedString; } d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++]; d->description = readStringField(data, d->textEncoding, &pos); d->data = data.mid(pos); } AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h) { // set v2.2 header to make fieldData work correctly setHeader(h, true); parseFields(fieldData(data)); // now set the v2.4 header Frame::Header *newHeader = new Frame::Header("APIC"); newHeader->setFrameSize(h->frameSize()); setHeader(newHeader, true); } �������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/attachedpictureframe.h����������������������������������������0000664�0000000�0000000�00000016512�12225024651�0023723�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ATTACHEDPICTUREFRAME_H #define TAGLIB_ATTACHEDPICTUREFRAME_H #include "id3v2frame.h" #include "id3v2header.h" #include "taglib_export.h" 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 TAGLIB_EXPORT 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 a text description of the image. * * \see setDescription() * \see textEncoding() * \see setTextEncoding() */ String description() const; /*! * Sets a textual description of the image to \a desc. * * \see description() * \see textEncoding() * \see setTextEncoding() */ void setDescription(const String &desc); /*! * 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; class AttachedPictureFramePrivate; AttachedPictureFramePrivate *d; private: AttachedPictureFrame(const AttachedPictureFrame &); AttachedPictureFrame &operator=(const AttachedPictureFrame &); AttachedPictureFrame(const ByteVector &data, Header *h); }; //! support for ID3v2.2 PIC frames class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame { protected: virtual void parseFields(const ByteVector &data); private: AttachedPictureFrameV22(const ByteVector &data, Header *h); friend class FrameFactory; }; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/commentsframe.cpp���������������������������������������������0000664�0000000�0000000�00000013211�12225024651�0022723�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevectorlist.h> #include <id3v2tag.h> #include <tdebug.h> #include <tstringlist.h> #include "commentsframe.h" #include "tpropertymap.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; } PropertyMap CommentsFrame::asProperties() const { String key = description().upper(); PropertyMap map; if(key.isEmpty() || key == "COMMENT") map.insert("COMMENT", text()); else if(key.isNull()) map.unsupportedData().append(L"COMM/" + description()); else map.insert("COMMENT:" + key, text()); return map; } CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static { ID3v2::FrameList comments = tag->frameList("COMM"); for(ID3v2::FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it); if(frame && frame->description() == d) return frame; } return 0; } //////////////////////////////////////////////////////////////////////////////// // 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, 2); if(l.size() == 2) { if(d->textEncoding == String::Latin1) { d->description = Tag::latin1StringHandler()->parse(l.front()); d->text = Tag::latin1StringHandler()->parse(l.back()); } else { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); } } } ByteVector CommentsFrame::renderFields() const { ByteVector v; String::Type encoding = d->textEncoding; encoding = checkTextEncoding(d->description, encoding); encoding = checkTextEncoding(d->text, encoding); v.append(char(encoding)); v.append(d->language.size() == 3 ? d->language : "XXX"); v.append(d->description.data(encoding)); v.append(textDelimiter(encoding)); v.append(d->text.data(encoding)); return v; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h) { d = new CommentsFramePrivate(); parseFields(fieldData(data)); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/commentsframe.h�����������������������������������������������0000664�0000000�0000000�00000013374�12225024651�0022402�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_COMMENTSFRAME_H #define TAGLIB_COMMENTSFRAME_H #include "id3v2frame.h" #include "taglib_export.h" 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 TAGLIB_EXPORT 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 * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>. * * \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 * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> 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); /*! * Parses this frame as PropertyMap with a single key. * - if description() is empty or "COMMENT", the key will be "COMMENT" * - if description() is not a valid PropertyMap key, the frame will be * marked unsupported by an entry "COMM/<description>" in the unsupportedData() * attribute of the returned map. * - otherwise, the key will be "COMMENT:<description>" * - The single value will be the frame's text(). */ PropertyMap asProperties() const; /*! * Comments each have a unique description. This searches for a comment * frame with the decription \a d and returns a pointer to it. If no * frame is found that matches the given description null is returned. * * \see description() */ static CommentsFrame *findByDescription(const Tag *tag, const String &d); 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 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp����������������������������0000664�0000000�0000000�00000012522�12225024651�0026277�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org copyright : (C) 2006 by Aaron VonderHaar email : avh4@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include "generalencapsulatedobjectframe.h" using namespace TagLib; using namespace ID3v2; class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate { public: GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; String mimeType; String fileName; String description; ByteVector data; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB") { d = new GeneralEncapsulatedObjectFramePrivate; } GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data) { d = new GeneralEncapsulatedObjectFramePrivate; setData(data); } GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame() { delete d; } String GeneralEncapsulatedObjectFrame::toString() const { String text = "[" + d->mimeType + "]"; if(!d->fileName.isEmpty()) text += " " + d->fileName; if(!d->description.isEmpty()) text += " \"" + d->description + "\""; return text; } String::Type GeneralEncapsulatedObjectFrame::textEncoding() const { return d->textEncoding; } void GeneralEncapsulatedObjectFrame::setTextEncoding(String::Type encoding) { d->textEncoding = encoding; } String GeneralEncapsulatedObjectFrame::mimeType() const { return d->mimeType; } void GeneralEncapsulatedObjectFrame::setMimeType(const String &type) { d->mimeType = type; } String GeneralEncapsulatedObjectFrame::fileName() const { return d->fileName; } void GeneralEncapsulatedObjectFrame::setFileName(const String &name) { d->fileName = name; } String GeneralEncapsulatedObjectFrame::description() const { return d->description; } void GeneralEncapsulatedObjectFrame::setDescription(const String &desc) { d->description = desc; } ByteVector GeneralEncapsulatedObjectFrame::object() const { return d->data; } void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data) { d->data = data; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) { if(data.size() < 4) { debug("An object frame must contain at least 4 bytes."); return; } d->textEncoding = String::Type(data[0]); int pos = 1; d->mimeType = readStringField(data, String::Latin1, &pos); d->fileName = readStringField(data, d->textEncoding, &pos); d->description = readStringField(data, d->textEncoding, &pos); d->data = data.mid(pos); } ByteVector GeneralEncapsulatedObjectFrame::renderFields() const { ByteVector data; data.append(char(d->textEncoding)); data.append(d->mimeType.data(String::Latin1)); data.append(textDelimiter(String::Latin1)); data.append(d->fileName.data(d->textEncoding)); data.append(textDelimiter(d->textEncoding)); data.append(d->description.data(d->textEncoding)); data.append(textDelimiter(d->textEncoding)); data.append(d->data); return data; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h) { d = new GeneralEncapsulatedObjectFramePrivate; parseFields(fieldData(data)); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h������������������������������0000664�0000000�0000000�00000013474�12225024651�0025753�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org copyright : (C) 2006 by Aaron VonderHaar email : avh4@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_GENERALENCAPSULATEDOBJECT_H #define TAGLIB_GENERALENCAPSULATEDOBJECT_H #include "id3v2frame.h" #include "id3v2header.h" #include "taglib_export.h" namespace TagLib { namespace ID3v2 { //! An ID3v2 general encapsulated object frame implementation /*! * This is an implementation of ID3v2 general encapsulated objects. * Arbitrary binary data may be included in tags, stored in GEOB frames. * There may be multiple GEOB frames in a single tag. Each GEOB it * labelled with a content description (which may be blank), a required * mime-type, and a file name (may be blank). The content description * uniquely identifies the GEOB frame in the tag. */ class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame { friend class FrameFactory; public: /*! * Constructs an empty object frame. The description, file name and text * encoding should be set manually. */ GeneralEncapsulatedObjectFrame(); /*! * Constructs a GeneralEncapsulatedObjectFrame frame based on \a data. * * \warning This is \em not data for the encapsulated object, for that use * setObject(). This constructor is used when reading the frame from the * disk. */ explicit GeneralEncapsulatedObjectFrame(const ByteVector &data); /*! * Destroys the GeneralEncapsulatedObjectFrame instance. */ virtual ~GeneralEncapsulatedObjectFrame(); /*! * Returns a string containing the description, file name and mime-type */ virtual String toString() const; /*! * Returns the text encoding used for the description and file name. * * \see setTextEncoding() * \see description() * \see fileName() */ String::Type textEncoding() const; /*! * Set the text encoding used for the description and file name. * * \see description() * \see fileName() */ void setTextEncoding(String::Type encoding); /*! * Returns the mime type of the object. */ String mimeType() const; /*! * Sets the mime type of the object. */ void setMimeType(const String &type); /*! * Returns the file name of the object. * * \see setFileName() */ String fileName() const; /*! * Sets the file name for the object. * * \see fileName() */ void setFileName(const String &name); /*! * Returns the content description of the object. * * \see setDescription() * \see textEncoding() * \see setTextEncoding() */ String description() const; /*! * Sets the content description of the object to \a desc. * * \see description() * \see textEncoding() * \see setTextEncoding() */ void setDescription(const String &desc); /*! * Returns the object 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 setObject() * \see mimeType() */ ByteVector object() const; /*! * Sets the object data to \a data. \a data should be of the type specified in * this frame's mime-type specification. * * \see object() * \see mimeType() * \see setMimeType() */ void setObject(const ByteVector &object); protected: virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; private: GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h); GeneralEncapsulatedObjectFrame(const GeneralEncapsulatedObjectFrame &); GeneralEncapsulatedObjectFrame &operator=(const GeneralEncapsulatedObjectFrame &); class GeneralEncapsulatedObjectFramePrivate; GeneralEncapsulatedObjectFramePrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/ownershipframe.cpp��������������������������������������������0000664�0000000�0000000�00000011255�12225024651�0023122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Rupert Daniel email : rupert@cancelmonday.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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include "ownershipframe.h" #include <id3v2tag.h> using namespace TagLib; using namespace ID3v2; class OwnershipFrame::OwnershipFramePrivate { public: String pricePaid; String datePurchased; String seller; String::Type textEncoding; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE") { d = new OwnershipFramePrivate; d->textEncoding = encoding; } OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data) { d = new OwnershipFramePrivate; setData(data); } OwnershipFrame::~OwnershipFrame() { delete d; } String OwnershipFrame::toString() const { return "pricePaid=" + d->pricePaid + " datePurchased=" + d->datePurchased + " seller=" + d->seller; } String OwnershipFrame::pricePaid() const { return d->pricePaid; } void OwnershipFrame::setPricePaid(const String &s) { d->pricePaid = s; } String OwnershipFrame::datePurchased() const { return d->datePurchased; } void OwnershipFrame::setDatePurchased(const String &s) { d->datePurchased = s; } String OwnershipFrame::seller() const { return d->seller; } void OwnershipFrame::setSeller(const String &s) { d->seller = s; } String::Type OwnershipFrame::textEncoding() const { return d->textEncoding; } void OwnershipFrame::setTextEncoding(String::Type encoding) { d->textEncoding = encoding; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void OwnershipFrame::parseFields(const ByteVector &data) { int pos = 0; // Get the text encoding d->textEncoding = String::Type(data[0]); pos += 1; // Read the price paid this is a null terminate string d->pricePaid = readStringField(data, String::Latin1, &pos); // If we don't have at least 8 bytes left then don't parse the rest of the // data if(data.size() - pos < 8) { return; } // Read the date purchased YYYYMMDD d->datePurchased = String(data.mid(pos, 8)); pos += 8; // Read the seller if(d->textEncoding == String::Latin1) d->seller = Tag::latin1StringHandler()->parse(data.mid(pos)); else d->seller = String(data.mid(pos), d->textEncoding); } ByteVector OwnershipFrame::renderFields() const { ByteVector v; v.append(char(d->textEncoding)); v.append(d->pricePaid.data(String::Latin1)); v.append(textDelimiter(String::Latin1)); v.append(d->datePurchased.data(String::Latin1)); v.append(d->seller.data(d->textEncoding)); return v; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h) { d = new OwnershipFramePrivate; parseFields(fieldData(data)); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/ownershipframe.h����������������������������������������������0000664�0000000�0000000�00000010722�12225024651�0022565�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Rupert Daniel email : rupert@cancelmonday.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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_OWNERSHIPFRAME_H #define TAGLIB_OWNERSHIPFRAME_H #include "id3v2frame.h" #include "taglib_export.h" namespace TagLib { namespace ID3v2 { //! An implementation of ID3v2 "ownership" /*! * This implements the ID3v2 ownership (OWNE frame). It consists of * a price paid, a date purchased (YYYYMMDD) and the name of the seller. */ class TAGLIB_EXPORT OwnershipFrame : public Frame { friend class FrameFactory; public: /*! * Construct an empty ownership frame. */ explicit OwnershipFrame(String::Type encoding = String::Latin1); /*! * Construct a ownership based on the data in \a data. */ explicit OwnershipFrame(const ByteVector &data); /*! * Destroys this OwnershipFrame instance. */ virtual ~OwnershipFrame(); /*! * Returns the text of this popularimeter. * * \see text() */ virtual String toString() const; /*! * Returns the date purchased. * * \see setDatePurchased() */ String datePurchased() const; /*! * Set the date purchased. * * \see datePurchased() */ void setDatePurchased(const String &datePurchased); /*! * Returns the price paid. * * \see setPricePaid() */ String pricePaid() const; /*! * Set the price paid. * * \see pricePaid() */ void setPricePaid(const String &pricePaid); /*! * Returns the seller. * * \see setSeller() */ String seller() const; /*! * Set the seller. * * \see seller() */ void setSeller(const String &seller); /*! * 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. */ OwnershipFrame(const ByteVector &data, Header *h); OwnershipFrame(const OwnershipFrame &); OwnershipFrame &operator=(const OwnershipFrame &); class OwnershipFramePrivate; OwnershipFramePrivate *d; }; } } #endif ����������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/popularimeterframe.cpp����������������������������������������0000664�0000000�0000000�00000010131�12225024651�0023764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Lukas Lalinsky email : lalinsky@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include "popularimeterframe.h" using namespace TagLib; using namespace ID3v2; class PopularimeterFrame::PopularimeterFramePrivate { public: PopularimeterFramePrivate() : rating(0), counter(0) {} String email; int rating; TagLib::uint counter; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// PopularimeterFrame::PopularimeterFrame() : Frame("POPM") { d = new PopularimeterFramePrivate; } PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data) { d = new PopularimeterFramePrivate; setData(data); } PopularimeterFrame::~PopularimeterFrame() { delete d; } String PopularimeterFrame::toString() const { return d->email + " rating=" + String::number(d->rating) + " counter=" + String::number(d->counter); } String PopularimeterFrame::email() const { return d->email; } void PopularimeterFrame::setEmail(const String &s) { d->email = s; } int PopularimeterFrame::rating() const { return d->rating; } void PopularimeterFrame::setRating(int s) { d->rating = s; } TagLib::uint PopularimeterFrame::counter() const { return d->counter; } void PopularimeterFrame::setCounter(TagLib::uint s) { d->counter = s; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void PopularimeterFrame::parseFields(const ByteVector &data) { int pos = 0, size = int(data.size()); d->email = readStringField(data, String::Latin1, &pos); d->rating = 0; d->counter = 0; if(pos < size) { d->rating = (unsigned char)(data[pos++]); if(pos < size) { d->counter = data.toUInt(static_cast<uint>(pos)); } } } ByteVector PopularimeterFrame::renderFields() const { ByteVector data; data.append(d->email.data(String::Latin1)); data.append(textDelimiter(String::Latin1)); data.append(char(d->rating)); data.append(ByteVector::fromUInt(d->counter)); return data; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h) { d = new PopularimeterFramePrivate; parseFields(fieldData(data)); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/popularimeterframe.h������������������������������������������0000664�0000000�0000000�00000007460�12225024651�0023444�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Lukas Lalinsky email : lalinsky@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_POPULARIMETERFRAME_H #define TAGLIB_POPULARIMETERFRAME_H #include "id3v2frame.h" #include "taglib_export.h" namespace TagLib { namespace ID3v2 { //! An implementation of ID3v2 "popularimeter" /*! * This implements the ID3v2 popularimeter (POPM frame). It concists of * an email, a rating and an optional counter. */ class TAGLIB_EXPORT PopularimeterFrame : public Frame { friend class FrameFactory; public: /*! * Construct an empty popularimeter frame. */ explicit PopularimeterFrame(); /*! * Construct a popularimeter based on the data in \a data. */ explicit PopularimeterFrame(const ByteVector &data); /*! * Destroys this PopularimeterFrame instance. */ virtual ~PopularimeterFrame(); /*! * Returns the text of this popularimeter. * * \see text() */ virtual String toString() const; /*! * Returns the email. * * \see setEmail() */ String email() const; /*! * Set the email. * * \see email() */ void setEmail(const String &email); /*! * Returns the rating. * * \see setRating() */ int rating() const; /*! * Set the rating. * * \see rating() */ void setRating(int rating); /*! * Returns the counter. * * \see setCounter() */ uint counter() const; /*! * Set the counter. * * \see counter() */ void setCounter(uint counter); protected: // Reimplementations. virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; private: /*! * The constructor used by the FrameFactory. */ PopularimeterFrame(const ByteVector &data, Header *h); PopularimeterFrame(const PopularimeterFrame &); PopularimeterFrame &operator=(const PopularimeterFrame &); class PopularimeterFramePrivate; PopularimeterFramePrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/privateframe.cpp����������������������������������������������0000664�0000000�0000000�00000007422�12225024651�0022557�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Serkan Kalyoncu copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevectorlist.h> #include <id3v2tag.h> #include <tdebug.h> #include "privateframe.h" using namespace TagLib; using namespace ID3v2; class PrivateFrame::PrivateFramePrivate { public: ByteVector data; String owner; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// PrivateFrame::PrivateFrame() : Frame("PRIV") { d = new PrivateFramePrivate; } PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data) { d = new PrivateFramePrivate; setData(data); } PrivateFrame::~PrivateFrame() { delete d; } String PrivateFrame::toString() const { return d->owner; } String PrivateFrame::owner() const { return d->owner; } ByteVector PrivateFrame::data() const { return d->data; } void PrivateFrame::setOwner(const String &s) { d->owner = s; } void PrivateFrame::setData(const ByteVector & data) { d->data = data; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void PrivateFrame::parseFields(const ByteVector &data) { if(data.size() < 2) { debug("A private frame must contain at least 2 bytes."); return; } // Owner identifier is assumed to be Latin1 const int byteAlign = 1; const int endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign); d->owner = String(data.mid(0, endOfOwner)); d->data = data.mid(endOfOwner + 1); } ByteVector PrivateFrame::renderFields() const { ByteVector v; v.append(d->owner.data(String::Latin1)); v.append(textDelimiter(String::Latin1)); v.append(d->data); return v; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h) { d = new PrivateFramePrivate(); parseFields(fieldData(data)); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/privateframe.h������������������������������������������������0000664�0000000�0000000�00000007027�12225024651�0022225�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Serkan Kalyoncu copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_PRIVATEFRAME_H #define TAGLIB_PRIVATEFRAME_H #include "id3v2frame.h" #include "taglib_export.h" namespace TagLib { namespace ID3v2 { //! An implementation of ID3v2 privateframe class TAGLIB_EXPORT PrivateFrame : public Frame { friend class FrameFactory; public: /*! * Construct an empty private frame. */ PrivateFrame(); /*! * Construct a private frame based on the data in \a data. * * \note This is the constructor used when parsing the frame from a file. */ explicit PrivateFrame(const ByteVector &data); /*! * Destroys this private frame instance. */ virtual ~PrivateFrame(); /*! * Returns the text of this private frame, currently just the owner. * * \see text() */ virtual String toString() const; /*! * \return The owner of the private frame. * \note This should contain an email address or link to a website. */ String owner() const; /*! * */ ByteVector data() const; /*! * Sets the owner of the frame to \a s. * \note This should contain an email address or link to a website. */ void setOwner(const String &s); /*! * */ void setData(const ByteVector &v); protected: // Reimplementations. virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; private: /*! * The constructor used by the FrameFactory. */ PrivateFrame(const ByteVector &data, Header *h); PrivateFrame(const PrivateFrame &); PrivateFrame &operator=(const PrivateFrame &); class PrivateFramePrivate; PrivateFramePrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp���������������������������������������0000664�0000000�0000000�00000015276�12225024651�0024156�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tmap.h> #include "relativevolumeframe.h" using namespace TagLib; using namespace ID3v2; static inline int bitsToBytes(int i) { return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1; } struct ChannelData { ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {} RelativeVolumeFrame::ChannelType channelType; short volumeAdjustment; RelativeVolumeFrame::PeakVolume peakVolume; }; class RelativeVolumeFrame::RelativeVolumeFramePrivate { public: String identification; Map<ChannelType, ChannelData> channels; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2") { d = new RelativeVolumeFramePrivate; } RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data) { d = new RelativeVolumeFramePrivate; setData(data); } RelativeVolumeFrame::~RelativeVolumeFrame() { delete d; } String RelativeVolumeFrame::toString() const { return d->identification; } List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const { List<ChannelType> l; Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin(); for(; it != d->channels.end(); ++it) l.append((*it).first); return l; } // deprecated RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const { return MasterVolume; } // deprecated void RelativeVolumeFrame::setChannelType(ChannelType) { } short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const { return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0; } short RelativeVolumeFrame::volumeAdjustmentIndex() const { return volumeAdjustmentIndex(MasterVolume); } void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type) { d->channels[type].volumeAdjustment = index; } void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index) { setVolumeAdjustmentIndex(index, MasterVolume); } float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const { return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0; } float RelativeVolumeFrame::volumeAdjustment() const { return volumeAdjustment(MasterVolume); } void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type) { d->channels[type].volumeAdjustment = short(adjustment * float(512)); } void RelativeVolumeFrame::setVolumeAdjustment(float adjustment) { setVolumeAdjustment(adjustment, MasterVolume); } RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const { return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume(); } RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const { return peakVolume(MasterVolume); } void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type) { d->channels[type].peakVolume = peak; } void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak) { setPeakVolume(peak, MasterVolume); } String RelativeVolumeFrame::identification() const { return d->identification; } void RelativeVolumeFrame::setIdentification(const String &s) { d->identification = s; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void RelativeVolumeFrame::parseFields(const ByteVector &data) { int pos = 0; d->identification = readStringField(data, String::Latin1, &pos); // Each channel is at least 4 bytes. while(pos <= (int)data.size() - 4) { ChannelType type = ChannelType(data[pos]); pos += 1; ChannelData &channel = d->channels[type]; channel.volumeAdjustment = data.toShort(static_cast<uint>(pos)); pos += 2; channel.peakVolume.bitsRepresentingPeak = data[pos]; pos += 1; int bytes = bitsToBytes(channel.peakVolume.bitsRepresentingPeak); channel.peakVolume.peakVolume = data.mid(pos, bytes); pos += bytes; } } ByteVector RelativeVolumeFrame::renderFields() const { ByteVector data; data.append(d->identification.data(String::Latin1)); data.append(textDelimiter(String::Latin1)); Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin(); for(; it != d->channels.end(); ++it) { ChannelType type = (*it).first; const ChannelData &channel = (*it).second; data.append(char(type)); data.append(ByteVector::fromShort(channel.volumeAdjustment)); data.append(char(channel.peakVolume.bitsRepresentingPeak)); data.append(channel.peakVolume.peakVolume); } return data; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h) { d = new RelativeVolumeFramePrivate; parseFields(fieldData(data)); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/relativevolumeframe.h�����������������������������������������0000664�0000000�0000000�00000022452�12225024651�0023615�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_RELATIVEVOLUMEFRAME_H #define TAGLIB_RELATIVEVOLUMEFRAME_H #include "tlist.h" #include "id3v2frame.h" #include "taglib_export.h" namespace TagLib { namespace ID3v2 { //! An ID3v2 relative volume adjustment frame implementation /*! * This is an implementation of ID3v2 relative volume adjustment. The * presence 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 TAGLIB_EXPORT 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 a list of channels with information currently in the frame. */ List<ChannelType> channels() const; /*! * \deprecated Always returns master volume. */ ChannelType channelType() const; /*! * \deprecated This method no longer has any effect. */ void setChannelType(ChannelType t); /* * There was a terrible API goof here, and while this can't be changed to * the way it appears below for binary compaibility reasons, let's at * least pretend that it looks clean. */ #ifdef DOXYGEN /*! * 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. * * This defaults to returning the value for the master volume channel if * available and returns 0 if the specified channel does not exist. * * \see setVolumeAdjustmentIndex() * \see volumeAjustment() */ short volumeAdjustmentIndex(ChannelType type = MasterVolume) 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. * * By default this sets the value for the master volume. * * \see volumeAdjustmentIndex() * \see setVolumeAjustment() */ void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume); /*! * 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(). * * This defaults to returning the value for the master volume channel if * available and returns 0 if the specified channel does not exist. * * \see setVolumeAdjustment() * \see volumeAdjustmentIndex() */ float volumeAdjustment(ChannelType type = MasterVolume) const; /*! * Set the relative volume adjustment in decibels to \a adjustment. * * By default this sets the value for the master volume. * * \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, ChannelType type = MasterVolume); /*! * Returns the peak volume (represented as a length and a string of bits). * * This defaults to returning the value for the master volume channel if * available and returns 0 if the specified channel does not exist. * * \see setPeakVolume() */ PeakVolume peakVolume(ChannelType type = MasterVolume) const; /*! * Sets the peak volume to \a peak. * * By default this sets the value for the master volume. * * \see peakVolume() */ void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume); #else // BIC: Combine each of the following pairs of functions (or maybe just // rework this junk altogether). short volumeAdjustmentIndex(ChannelType type) const; short volumeAdjustmentIndex() const; void setVolumeAdjustmentIndex(short index, ChannelType type); void setVolumeAdjustmentIndex(short index); float volumeAdjustment(ChannelType type) const; float volumeAdjustment() const; void setVolumeAdjustment(float adjustment, ChannelType type); void setVolumeAdjustment(float adjustment); PeakVolume peakVolume(ChannelType type) const; PeakVolume peakVolume() const; void setPeakVolume(const PeakVolume &peak, ChannelType type); void setPeakVolume(const PeakVolume &peak); #endif /*! * Returns the identification for this frame. */ String identification() const; /*! * Sets the identification of the frame to \a s. The string * is used to identify the situation and/or device where this * adjustment should apply. */ void setIdentification(const String &s); 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 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/textidentificationframe.cpp�����������������������������������0000664�0000000�0000000�00000031275�12225024651�0025006�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevectorlist.h> #include <id3v2tag.h> #include "textidentificationframe.h" #include "tpropertymap.h" #include "id3v1genres.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::createTIPLFrame(const PropertyMap &properties) // static { TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL"); StringList l; for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ l.append(it->first); l.append(it->second.toString(",")); // comma-separated list of names } frame->setText(l); return frame; } TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static { TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL"); StringList l; for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ if(!it->first.startsWith(instrumentPrefix)) // should not happen continue; l.append(it->first.substr(instrumentPrefix.size())); l.append(it->second.toString(",")); } frame->setText(l); return frame; } 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; } // array of allowed TIPL prefixes and their corresponding key value static const TagLib::uint involvedPeopleSize = 5; static const char* involvedPeople[][2] = { {"ARRANGER", "ARRANGER"}, {"ENGINEER", "ENGINEER"}, {"PRODUCER", "PRODUCER"}, {"DJ-MIX", "DJMIXER"}, {"MIX", "MIXER"}, }; const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static { static KeyConversionMap m; if(m.isEmpty()) for(uint i = 0; i < involvedPeopleSize; ++i) m.insert(involvedPeople[i][1], involvedPeople[i][0]); return m; } PropertyMap TextIdentificationFrame::asProperties() const { if(frameID() == "TIPL") return makeTIPLProperties(); if(frameID() == "TMCL") return makeTMCLProperties(); PropertyMap map; String tagName = frameIDToKey(frameID()); if(tagName.isNull()) { map.unsupportedData().append(frameID()); return map; } StringList values = fieldList(); if(tagName == "GENRE") { // Special case: Support ID3v1-style genre numbers. They are not officially supported in // ID3v2, however it seems that still a lot of programs use them. for(StringList::Iterator it = values.begin(); it != values.end(); ++it) { bool ok = false; int test = it->toInt(&ok); // test if the genre value is an integer if(ok) *it = ID3v1::genre(test); } } else if(tagName == "DATE") { for(StringList::Iterator it = values.begin(); it != values.end(); ++it) { // ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time. // Since this is unusual in other formats, the T is removed. int tpos = it->find("T"); if(tpos != -1) (*it)[tpos] = ' '; } } PropertyMap ret; ret.insert(tagName, values); return ret; } //////////////////////////////////////////////////////////////////////////////// // TextIdentificationFrame protected members //////////////////////////////////////////////////////////////////////////////// void TextIdentificationFrame::parseFields(const ByteVector &data) { // Don't try to parse invalid frames if(data.size() < 2) return; // 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; // build a small counter to strip nulls off the end of the field int dataLength = data.size() - 1; while(dataLength > 0 && data[dataLength] == 0) dataLength--; while(dataLength % byteAlign != 0) dataLength++; ByteVectorList l = ByteVectorList::split(data.mid(1, dataLength), 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++) { if(!(*it).isEmpty()) { if(d->textEncoding == String::Latin1) d->fieldList.append(Tag::latin1StringHandler()->parse(*it)); else d->fieldList.append(String(*it, d->textEncoding)); } } } ByteVector TextIdentificationFrame::renderFields() const { String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding); ByteVector v; v.append(char(encoding)); for(StringList::ConstIterator 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(encoding)); v.append((*it).data(encoding)); } return v; } //////////////////////////////////////////////////////////////////////////////// // TextIdentificationFrame private members //////////////////////////////////////////////////////////////////////////////// TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h) { d = new TextIdentificationFramePrivate; parseFields(fieldData(data)); } PropertyMap TextIdentificationFrame::makeTIPLProperties() const { PropertyMap map; if(fieldList().size() % 2 != 0){ // according to the ID3 spec, TIPL must contain an even number of entries map.unsupportedData().append(frameID()); return map; } StringList l = fieldList(); for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) { bool found = false; for(uint i = 0; i < involvedPeopleSize; ++i) if(*it == involvedPeople[i][0]) { map.insert(involvedPeople[i][1], (++it)->split(",")); found = true; break; } if(!found){ // invalid involved role -> mark whole frame as unsupported in order to be consisten with writing map.clear(); map.unsupportedData().append(frameID()); return map; } } return map; } PropertyMap TextIdentificationFrame::makeTMCLProperties() const { PropertyMap map; if(fieldList().size() % 2 != 0){ // according to the ID3 spec, TMCL must contain an even number of entries map.unsupportedData().append(frameID()); return map; } StringList l = fieldList(); for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) { String instrument = it->upper(); if(instrument.isNull()) { // instrument is not a valid key -> frame unsupported map.clear(); map.unsupportedData().append(frameID()); return map; } map.insert(L"PERFORMER:" + instrument, (++it)->split(",")); } return map; } //////////////////////////////////////////////////////////////////////////////// // 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) { checkFields(); } UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : TextIdentificationFrame("TXXX", encoding), d(0) { setDescription(description); setText(values); } 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 { // TODO: remove this function return TextIdentificationFrame::fieldList(); } 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); } PropertyMap UserTextIdentificationFrame::asProperties() const { PropertyMap map; String tagName = txxxToKey(description()); StringList v = fieldList(); for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it) if(it != v.begin()) map.insert(tagName, *it); return map; } UserTextIdentificationFrame *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<UserTextIdentificationFrame *>(*it); if(f && f->description() == description) return f; } return 0; } //////////////////////////////////////////////////////////////////////////////// // UserTextIdentificationFrame private members //////////////////////////////////////////////////////////////////////////////// UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) : TextIdentificationFrame(data, h) { checkFields(); } void UserTextIdentificationFrame::checkFields() { int fields = fieldList().size(); if(fields == 0) setDescription(String::null); if(fields <= 1) setText(String::null); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/textidentificationframe.h�������������������������������������0000664�0000000�0000000�00000030417�12225024651�0024450�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_TEXTIDENTIFICATIONFRAME_H #define TAGLIB_TEXTIDENTIFICATIONFRAME_H #include "tstringlist.h" #include "tmap.h" #include "taglib_export.h" #include "id3v2frame.h" namespace TagLib { namespace ID3v2 { class Tag; typedef Map<String, String> KeyConversionMap; //! 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: * * <ul> * <li><b>TALB</b> Album/Movie/Show title</li> * <li><b>TBPM</b> BPM (beats per minute)</li> * <li><b>TCOM</b> Composer</li> * <li><b>TCON</b> Content type</li> * <li><b>TCOP</b> Copyright message</li> * <li><b>TDEN</b> Encoding time</li> * <li><b>TDLY</b> Playlist delay</li> * <li><b>TDOR</b> Original release time</li> * <li><b>TDRC</b> Recording time</li> * <li><b>TDRL</b> Release time</li> * <li><b>TDTG</b> Tagging time</li> * <li><b>TENC</b> Encoded by</li> * <li><b>TEXT</b> Lyricist/Text writer</li> * <li><b>TFLT</b> File type</li> * <li><b>TIPL</b> Involved people list</li> * <li><b>TIT1</b> Content group description</li> * <li><b>TIT2</b> Title/songname/content description</li> * <li><b>TIT3</b> Subtitle/Description refinement</li> * <li><b>TKEY</b> Initial key</li> * <li><b>TLAN</b> Language(s)</li> * <li><b>TLEN</b> Length</li> * <li><b>TMCL</b> Musician credits list</li> * <li><b>TMED</b> Media type</li> * <li><b>TMOO</b> Mood</li> * <li><b>TOAL</b> Original album/movie/show title</li> * <li><b>TOFN</b> Original filename</li> * <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li> * <li><b>TOPE</b> Original artist(s)/performer(s)</li> * <li><b>TOWN</b> File owner/licensee</li> * <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li> * <li><b>TPE2</b> Band/orchestra/accompaniment</li> * <li><b>TPE3</b> Conductor/performer refinement</li> * <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li> * <li><b>TPOS</b> Part of a set</li> * <li><b>TPRO</b> Produced notice</li> * <li><b>TPUB</b> Publisher</li> * <li><b>TRCK</b> Track number/Position in set</li> * <li><b>TRSN</b> Internet radio station name</li> * <li><b>TRSO</b> Internet radio station owner</li> * <li><b>TSOA</b> Album sort order</li> * <li><b>TSOP</b> Performer sort order</li> * <li><b>TSOT</b> Title sort order</li> * <li><b>TSRC</b> ISRC (international standard recording code)</li> * <li><b>TSSE</b> Software/Hardware and settings used for encoding</li> * <li><b>TSST</b> Set subtitle</li> * </ul> * * 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. * * \note If non-Latin1 compatible strings are used with this class, even if * the text encoding is set to Latin1, the frame will be written using UTF8 * (with the encoding flag appropriately set in the output). */ class TAGLIB_EXPORT 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. * * \note Please see the note in the class description regarding Latin1. */ 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); /*! * This is a special factory method to create a TIPL (involved people list) * frame from the given \a properties. Will parse key=[list of values] data * into the TIPL format as specified in the ID3 standard. */ static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties); /*! * This is a special factory method to create a TMCL (musician credits list) * frame from the given \a properties. Will parse key=[list of values] data * into the TMCL format as specified in the ID3 standard, where key should be * of the form instrumentPrefix:instrument. */ static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties); /*! * 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. * * \note Please see the note in the class description regarding Latin1. * * \see setTextEncoding() * \see render() */ String::Type textEncoding() const; /*! * Sets the text encoding to be used when rendering this frame to * \a encoding. * * \note Please see the note in the class description regarding Latin1. * * \see textEncoding() * \see render() */ void setTextEncoding(String::Type encoding); /*! * Returns a list of the strings in this frame. */ StringList fieldList() const; /*! * Returns a KeyConversionMap mapping a role as it would be used in a PropertyMap * to the corresponding key used in a TIPL ID3 frame to describe that role. */ static const KeyConversionMap &involvedPeopleMap(); PropertyMap asProperties() 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 &); /*! * Parses the special structure of a TIPL frame * Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER", * "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed. */ PropertyMap makeTIPLProperties() const; /*! * Parses the special structure of a TMCL frame. */ PropertyMap makeTMCLProperties() const; 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 TAGLIB_EXPORT 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); /*! * Creates a user defined text identification frame with the given \a description * and \a values. */ UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8); 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 presence 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); /*! * A UserTextIdentificationFrame is parsed into a PropertyMap as follows: * - the key is the frame's description, uppercased * - if the description contains '::', only the substring after that * separator is considered as key (compatibility with exfalso) * - if the above rules don't yield a valid key (e.g. containing non-ASCII * characters), the returned map will contain an entry "TXXX/<description>" * in its unsupportedData() list. * - The values will be copies of the fieldList(). * - If the description() appears as value in fieldList(), it will be omitted * in the value list, in order to be compatible with TagLib which copies * the description() into the fieldList(). */ PropertyMap asProperties() const; /*! * 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 &); void checkFields(); class UserTextIdentificationFramePrivate; UserTextIdentificationFramePrivate *d; }; } } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp���������������������������������0000664�0000000�0000000�00000010567�12225024651�0025322�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevectorlist.h> #include <tpropertymap.h> #include <tdebug.h> #include "id3v2tag.h" #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; } UniqueFileIdentifierFrame::~UniqueFileIdentifierFrame() { delete d; } 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; } PropertyMap UniqueFileIdentifierFrame::asProperties() const { PropertyMap map; if(d->owner == "http://musicbrainz.org") { map.insert("MUSICBRAINZ_TRACKID", String(d->identifier)); } else { map.unsupportedData().append(frameID() + String("/") + d->owner); } return map; } UniqueFileIdentifierFrame *UniqueFileIdentifierFrame::findByOwner(const ID3v2::Tag *tag, const String &o) // static { ID3v2::FrameList comments = tag->frameList("UFID"); for(ID3v2::FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { UniqueFileIdentifierFrame *frame = dynamic_cast<UniqueFileIdentifierFrame *>(*it); if(frame && frame->owner() == o) return frame; } return 0; } void UniqueFileIdentifierFrame::parseFields(const ByteVector &data) { if(data.size() < 1) { debug("An UFID frame must contain at least 1 byte."); return; } int pos = 0; d->owner = readStringField(data, String::Latin1, &pos); d->identifier = data.mid(pos); } 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)); } �����������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h�����������������������������������0000664�0000000�0000000�00000010466�12225024651�0024765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_UNIQUEFILEIDENTIFIERFRAME #define TAGLIB_UNIQUEFILEIDENTIFIERFRAME #include "id3v2frame.h" 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 TAGLIB_EXPORT 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); /*! * Destroys the frame. */ ~UniqueFileIdentifierFrame(); /*! * 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; PropertyMap asProperties() const; /*! * UFID frames each have a unique owner. This searches for a UFID * frame with the owner \a o and returns a pointer to it. * * \see owner() */ static UniqueFileIdentifierFrame *findByOwner(const Tag *tag, const String &o); protected: virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; private: UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame &); UniqueFileIdentifierFrame &operator=(const UniqueFileIdentifierFrame &); UniqueFileIdentifierFrame(const ByteVector &data, Header *h); class UniqueFileIdentifierFramePrivate; UniqueFileIdentifierFramePrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/unknownframe.cpp����������������������������������������������0000664�0000000�0000000�00000005712�12225024651�0022604�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "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)); } ������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/unknownframe.h������������������������������������������������0000664�0000000�0000000�00000006127�12225024651�0022252�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_UNKNOWNFRAME_H #define TAGLIB_UNKNOWNFRAME_H #include "id3v2frame.h" #include "taglib_export.h" 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 TAGLIB_EXPORT 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 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp���������������������������������0000664�0000000�0000000�00000013736�12225024651�0025422�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org copyright : (C) 2006 by Urs Fleisch email : ufleisch@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "unsynchronizedlyricsframe.h" #include <tbytevectorlist.h> #include <id3v2tag.h> #include <tdebug.h> #include <tpropertymap.h> using namespace TagLib; using namespace ID3v2; class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate { public: UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; ByteVector language; String description; String text; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) : Frame("USLT") { d = new UnsynchronizedLyricsFramePrivate; d->textEncoding = encoding; } UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) : Frame(data) { d = new UnsynchronizedLyricsFramePrivate; setData(data); } UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame() { delete d; } String UnsynchronizedLyricsFrame::toString() const { return d->text; } ByteVector UnsynchronizedLyricsFrame::language() const { return d->language; } String UnsynchronizedLyricsFrame::description() const { return d->description; } String UnsynchronizedLyricsFrame::text() const { return d->text; } void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding) { d->language = languageEncoding.mid(0, 3); } void UnsynchronizedLyricsFrame::setDescription(const String &s) { d->description = s; } void UnsynchronizedLyricsFrame::setText(const String &s) { d->text = s; } String::Type UnsynchronizedLyricsFrame::textEncoding() const { return d->textEncoding; } void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding) { d->textEncoding = encoding; } PropertyMap UnsynchronizedLyricsFrame::asProperties() const { PropertyMap map; String key = description().upper(); if(key.isEmpty() || key.upper() == "LYRICS") map.insert("LYRICS", text()); else if(key.isNull()) map.unsupportedData().append(L"USLT/" + description()); else map.insert("LYRICS:" + key, text()); return map; } UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static { ID3v2::FrameList lyrics = tag->frameList("USLT"); for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){ UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it); if(frame && frame->description() == d) return frame; } return 0; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data) { if(data.size() < 5) { debug("An unsynchronized lyrics 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, 2); if(l.size() == 2) { if(d->textEncoding == String::Latin1) { d->description = Tag::latin1StringHandler()->parse(l.front()); d->text = Tag::latin1StringHandler()->parse(l.back()); } else { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); } } } ByteVector UnsynchronizedLyricsFrame::renderFields() const { ByteVector v; v.append(char(d->textEncoding)); v.append(d->language.size() == 3 ? d->language : "XXX"); v.append(d->description.data(d->textEncoding)); v.append(textDelimiter(d->textEncoding)); v.append(d->text.data(d->textEncoding)); return v; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) : Frame(h) { d = new UnsynchronizedLyricsFramePrivate(); parseFields(fieldData(data)); } ����������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h�����������������������������������0000664�0000000�0000000�00000014216�12225024651�0025061�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org copyright : (C) 2006 by Urs Fleisch email : ufleisch@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H #define TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H #include "id3v2frame.h" namespace TagLib { namespace ID3v2 { //! ID3v2 unsynchronized lyrics frame /*! * An implementation of ID3v2 unsynchronized lyrics. */ class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame { friend class FrameFactory; public: /*! * Construct an empty unsynchronized lyrics frame that will use the text encoding * \a encoding. */ explicit UnsynchronizedLyricsFrame(String::Type encoding = String::Latin1); /*! * Construct a unsynchronized lyrics frame based on the data in \a data. */ explicit UnsynchronizedLyricsFrame(const ByteVector &data); /*! * Destroys this UnsynchronizedLyricsFrame instance. */ virtual ~UnsynchronizedLyricsFrame(); /*! * Returns the text of this unsynchronized lyrics frame. * * \see text() */ virtual String toString() const; /*! * Returns the language encoding as a 3 byte encoding as specified by * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>. * * \note Most taggers simply ignore this value. * * \see setLanguage() */ ByteVector language() const; /*! * Returns the description of this unsynchronized lyrics frame. * * \note Most taggers simply ignore this value. * * \see setDescription() */ String description() const; /*! * Returns the text of this unsynchronized lyrics frame. * * \see setText() */ String text() const; /*! * Set the language using the 3 byte language code from * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to * \a languageCode. * * \see language() */ void setLanguage(const ByteVector &languageCode); /*! * Sets the description of the unsynchronized lyrics frame to \a s. * * \see decription() */ void setDescription(const String &s); /*! * Sets the text portion of the unsynchronized lyrics frame 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); /*! Parses this frame as PropertyMap with a single key. * - if description() is empty or "LYRICS", the key will be "LYRICS" * - if description() is not a valid PropertyMap key, the frame will be * marked unsupported by an entry "USLT/<description>" in the unsupportedData() * attribute of the returned map. * - otherwise, the key will be "LYRICS:<description>" * - The single value will be the frame's text(). * Note that currently the language() field is not supported by the PropertyMap * interface. */ PropertyMap asProperties() const; /*! * LyricsFrames each have a unique description. This searches for a lyrics * frame with the decription \a d and returns a pointer to it. If no * frame is found that matches the given description null is returned. * * \see description() */ static UnsynchronizedLyricsFrame *findByDescription(const Tag *tag, const String &d); protected: // Reimplementations. virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; private: /*! * The constructor used by the FrameFactory. */ UnsynchronizedLyricsFrame(const ByteVector &data, Header *h); UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame &); UnsynchronizedLyricsFrame &operator=(const UnsynchronizedLyricsFrame &); class UnsynchronizedLyricsFramePrivate; UnsynchronizedLyricsFramePrivate *d; }; } } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/urllinkframe.cpp����������������������������������������������0000664�0000000�0000000�00000013460�12225024651�0022564�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org copyright : (C) 2006 by Urs Fleisch email : ufleisch@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "urllinkframe.h" #include "id3v2tag.h" #include <tdebug.h> #include <tstringlist.h> #include <tpropertymap.h> using namespace TagLib; using namespace ID3v2; class UrlLinkFrame::UrlLinkFramePrivate { public: String url; }; class UserUrlLinkFrame::UserUrlLinkFramePrivate { public: UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {} String::Type textEncoding; String description; }; UrlLinkFrame::UrlLinkFrame(const ByteVector &data) : Frame(data) { d = new UrlLinkFramePrivate; setData(data); } UrlLinkFrame::~UrlLinkFrame() { delete d; } void UrlLinkFrame::setUrl(const String &s) { d->url = s; } String UrlLinkFrame::url() const { return d->url; } void UrlLinkFrame::setText(const String &s) { setUrl(s); } String UrlLinkFrame::toString() const { return url(); } PropertyMap UrlLinkFrame::asProperties() const { String key = frameIDToKey(frameID()); PropertyMap map; if(key.isNull()) // unknown W*** frame - this normally shouldn't happen map.unsupportedData().append(frameID()); else map.insert(key, url()); return map; } void UrlLinkFrame::parseFields(const ByteVector &data) { d->url = String(data); } ByteVector UrlLinkFrame::renderFields() const { return d->url.data(String::Latin1); } UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h) { d = new UrlLinkFramePrivate; parseFields(fieldData(data)); } UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) : UrlLinkFrame("WXXX") { d = new UserUrlLinkFramePrivate; d->textEncoding = encoding; } UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) : UrlLinkFrame(data) { d = new UserUrlLinkFramePrivate; setData(data); } UserUrlLinkFrame::~UserUrlLinkFrame() { delete d; } String UserUrlLinkFrame::toString() const { return "[" + description() + "] " + url(); } String::Type UserUrlLinkFrame::textEncoding() const { return d->textEncoding; } void UserUrlLinkFrame::setTextEncoding(String::Type encoding) { d->textEncoding = encoding; } String UserUrlLinkFrame::description() const { return d->description; } void UserUrlLinkFrame::setDescription(const String &s) { d->description = s; } PropertyMap UserUrlLinkFrame::asProperties() const { PropertyMap map; String key = description().upper(); if(key.isEmpty() || key.upper() == "URL") map.insert("URL", url()); else if(key.isNull()) map.unsupportedData().append(L"WXXX/" + description()); else map.insert("URL:" + key, url()); return map; } UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static { FrameList l = tag->frameList("WXXX"); for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) { UserUrlLinkFrame *f = dynamic_cast<UserUrlLinkFrame *>(*it); if(f && f->description() == description) return f; } return 0; } void UserUrlLinkFrame::parseFields(const ByteVector &data) { if(data.size() < 2) { debug("A user URL link frame must contain at least 2 bytes."); return; } int pos = 0; d->textEncoding = String::Type(data[0]); pos += 1; if(d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) { int offset = data.find(textDelimiter(d->textEncoding), pos); if(offset < pos) return; d->description = String(data.mid(pos, offset - pos), d->textEncoding); pos = offset + 1; } else { int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2); if(len < 0) return; d->description = String(data.mid(pos, len), d->textEncoding); pos += len + 2; } setUrl(String(data.mid(pos))); } ByteVector UserUrlLinkFrame::renderFields() const { ByteVector v; String::Type encoding = checkTextEncoding(d->description, d->textEncoding); v.append(char(encoding)); v.append(d->description.data(encoding)); v.append(textDelimiter(encoding)); v.append(url().data(String::Latin1)); return v; } UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h) { d = new UserUrlLinkFramePrivate; parseFields(fieldData(data)); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/frames/urllinkframe.h������������������������������������������������0000664�0000000�0000000�00000014204�12225024651�0022226�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org copyright : (C) 2006 by Urs Fleisch email : ufleisch@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_URLLINKFRAME_H #define TAGLIB_URLLINKFRAME_H #include "id3v2frame.h" namespace TagLib { namespace ID3v2 { //! ID3v2 URL frame /*! * An implementation of ID3v2 URL link frames. */ class TAGLIB_EXPORT UrlLinkFrame : public Frame { friend class FrameFactory; public: /*! * 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 UrlLinkFrame(const ByteVector &data); /*! * Destroys this UrlLinkFrame instance. */ virtual ~UrlLinkFrame(); /*! * Returns the URL. */ virtual String url() const; /*! * Sets the URL to \a s. */ virtual void setUrl(const String &s); // Reimplementations. virtual void setText(const String &s); virtual String toString() const; PropertyMap asProperties() const; protected: virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; /*! * The constructor used by the FrameFactory. */ UrlLinkFrame(const ByteVector &data, Header *h); private: UrlLinkFrame(const UrlLinkFrame &); UrlLinkFrame &operator=(const UrlLinkFrame &); class UrlLinkFramePrivate; UrlLinkFramePrivate *d; }; //! ID3v2 User defined URL frame /*! * This is a specialization of URL link frames that allows for * user defined entries. Each entry has a description in addition to the * normal list of fields that a URL link frame has. * * This description identifies the frame and must be unique. */ class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame { friend class FrameFactory; public: /*! * Constructs an empty user defined URL link frame. For this to be * a useful frame both a description and text must be set. */ explicit UserUrlLinkFrame(String::Type encoding = String::Latin1); /*! * 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 UserUrlLinkFrame(const ByteVector &data); /*! * Destroys this UserUrlLinkFrame instance. */ virtual ~UserUrlLinkFrame(); // Reimplementations. 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 the description for this frame. */ String description() const; /*! * Sets the description of the frame to \a s. \a s must be unique. */ void setDescription(const String &s); /*! * Parses the UserUrlLinkFrame as PropertyMap. The description() is taken as key, * and the URL as single value. * - if description() is empty, the key will be "URL". * - otherwise, if description() is not a valid key (e.g. containing non-ASCII * characters), the returned map will contain an entry "WXXX/<description>" * in its unsupportedData() list. */ PropertyMap asProperties() const; /*! * Searches for the user defined url frame with the description \a description * in \a tag. This returns null if no matching frames were found. */ static UserUrlLinkFrame *find(Tag *tag, const String &description); protected: virtual void parseFields(const ByteVector &data); virtual ByteVector renderFields() const; /*! * The constructor used by the FrameFactory. */ UserUrlLinkFrame(const ByteVector &data, Header *h); private: UserUrlLinkFrame(const UserUrlLinkFrame &); UserUrlLinkFrame &operator=(const UserUrlLinkFrame &); class UserUrlLinkFramePrivate; UserUrlLinkFramePrivate *d; }; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2.2.0.txt��������������������������������������������������������0000664�0000000�0000000�00000171531�12225024651�0020102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ Informal standard M. Nilsson Document: id3v2-00.txt 26th March 1998 ID3 tag version 2 Status of this document This document is an Informal standard and is released so that implementors could have a set standard before the formal standard is set. The formal standard will use another version number if not identical to what is described in this document. The contents in this document may change for clarifications but never for added or altered functionallity. Distribution of this document is unlimited. Abstract The recent gain of popularity for MPEG layer III audio files on the internet forced a standardised way of storing information about an audio file within itself to determinate its origin and contents. Today the most accepted way to do this is with the so called ID3 tag, which is simple but very limited and in some cases very unsuitable. The ID3 tag has very limited space in every field, very limited numbers of fields, not expandable or upgradeable and is placed at the end of a the file, which is unsuitable for streaming audio. This draft is an attempt to answer these issues with a new version of the ID3 tag. 1. Table of contents 2. Conventions in this document 3. ID3v2 overview 3.1. ID3v2 header 3.2. ID3v2 frames overview 4. Declared ID3v2 frames 4.1. Unique file identifier 4.2. Text information frames 4.2.1. Text information frames - details 4.2.2. 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. Involved people list 4.5. Music CD Identifier 4.6. Event timing codes 4.7. MPEG location lookup table 4.8. Synced tempo codes 4.9. Unsychronised lyrics/text transcription 4.10. Synchronised lyrics/text 4.11. Comments 4.12. Relative volume adjustment 4.13. Equalisation 4.14. Reverb 4.15. Attached picture 4.16. General encapsulated object 4.17. Play counter 4.18. Popularimeter 4.19. Recommended buffer size 4.20. Encrypted meta frame 4.21. Audio encryption 4.22. Linked information 5. The 'unsynchronisation scheme' 6. Copyright 7. References 8. Appendix A. Appendix A - ID3-Tag Specification V1.1 A.1. Overview A.2. ID3v1 Implementation A.3. Genre List A.4. Track addition - ID3v1.1 9. Author's Address 2. Conventions in this document In the examples, text within "" is a text string exactly as it appears in a file. 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 0-9 only. 3. ID3v2 overview The two biggest design goals were to be able to implement ID3v2 without disturbing old software too much and that ID3v2 should be expandable. The first criterion is met by the simple fact that the MPEG [MPEG] decoding software uses a syncsignal, embedded in the audiostream, to 'lock on to' the audio. Since the ID3v2 tag doesn't contain a valid syncsignal, no software will attempt to play the tag. If, for any reason, coincidence make a syncsignal appear within the tag it will be taken care of by the 'unsynchronisation scheme' described in section 5. The second criterion has made a more noticeable impact on the design of the ID3v2 tag. It 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 there is an identifier that explains the frames's format and content, and a size descriptor that allows software to skip unknown frames. If a total revision of the ID3v2 tag should be needed, there is a version number and a size descriptor in the ID3v2 header. The ID3 tag described in this document is mainly targeted to files encoded with MPEG-2 layer I, MPEG-2 layer II, MPEG-2 layer III and MPEG-2.5, but may work with other types of encoded audio. 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). It is permitted to include padding after all 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 head of the tag. 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. 3.1. ID3v2 header The ID3v2 tag header, which should be the first information in the file, is 10 bytes as follows: ID3/file identifier "ID3" ID3 version $02 00 ID3 flags %xx000000 ID3 size 4 * %0xxxxxxx The first three bytes of the tag are always "ID3" to indicate that this is an ID3 tag, directly followed by the two version bytes. The first byte of ID3 version is it's major version, while the second byte is its revision number. All revisions are backwards compatible while major versions are not. If software with ID3v2 and below support should encounter version three or higher it should simply ignore the whole tag. Version and revision will never be $FF. The first bit (bit 7) in the 'ID3 flags' is indicating whether or not unsynchronisation is used (see section 5 for details); a set bit indicates usage. The second bit (bit 6) is indicating whether or not compression is used; a set bit indicates usage. Since no compression scheme has been decided yet, the ID3 decoder (for now) should just ignore the entire tag if the compression bit is set. The ID3 tag size is encoded with four bytes where the first bit (bit 7) is set to zero in every byte, making a total of 28 bits. The zeroed bits are ignored, so a 257 bytes long tag is represented as $00 00 02 01. The ID3 tag size is the size of the complete tag after unsychronisation, including padding, excluding the header (total tag size - 10). The reason to use 28 bits (representing up to 256MB) for size description is that we don't want to run out of space here. A 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. ID3v2 frames overview The headers of the frames are similar in their construction. They consist of one three character identifier (capital A-Z and 0-9) and one three byte size field, making a total of six bytes. The header is excluded from the size. Identifiers beginning with "X", "Y" and "Z" are for experimental use and free for everyone to use. Have 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 three character frame identifier is followed by a three byte size descriptor, making a total header size of six bytes in every frame. The size is calculated as framesize excluding frame identifier and size descriptor (frame size - 6). 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: UFI, MCI, TT2 ... A tag must contain at least one frame. A frame must be at least 1 byte big, excluding the 6-byte header. If nothing else is said a string is represented as ISO-8859-1 [ISO-8859-1] characters in the range $20 - $FF. All unicode strings [UNICODE] use 16-bit unicode 2.0 (ISO/IEC 10646-1:1993, UCS-2). All numeric strings are always encoded as ISO-8859-1. Terminated strings are terminated with $00 if encoded with ISO-8859-1 and $00 00 if encoded as unicode. If nothing else is said newline character is forbidden. In ISO-8859-1 a new line is represented, when allowed, with $0A only. Frames that allow different types of text encoding have a text encoding description byte directly after the frame size. If ISO-8859-1 is used this byte should be $00, if unicode is used it should be $01. The three byte language field is used to describe the language of the frame's content, according to ISO-639-2 [ISO-639-2]. 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 ID3 standard. This is reflected by the revision number in the header of the tag. 4. Declared ID3v2 frames The following frames are declared in this draft. 4.19 BUF Recommended buffer size 4.17 CNT Play counter 4.11 COM Comments 4.21 CRA Audio encryption 4.20 CRM Encrypted meta frame 4.6 ETC Event timing codes 4.13 EQU Equalization 4.16 GEO General encapsulated object 4.4 IPL Involved people list 4.22 LNK Linked information 4.5 MCI Music CD Identifier 4.7 MLL MPEG location lookup table 4.15 PIC Attached picture 4.18 POP Popularimeter 4.14 REV Reverb 4.12 RVA Relative volume adjustment 4.10 SLT Synchronized lyric/text 4.8 STC Synced tempo codes 4.2.1 TAL Album/Movie/Show title 4.2.1 TBP BPM (Beats Per Minute) 4.2.1 TCM Composer 4.2.1 TCO Content type 4.2.1 TCR Copyright message 4.2.1 TDA Date 4.2.1 TDY Playlist delay 4.2.1 TEN Encoded by 4.2.1 TFT File type 4.2.1 TIM Time 4.2.1 TKE Initial key 4.2.1 TLA Language(s) 4.2.1 TLE Length 4.2.1 TMT Media type 4.2.1 TOA Original artist(s)/performer(s) 4.2.1 TOF Original filename 4.2.1 TOL Original Lyricist(s)/text writer(s) 4.2.1 TOR Original release year 4.2.1 TOT Original album/Movie/Show title 4.2.1 TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group 4.2.1 TP2 Band/Orchestra/Accompaniment 4.2.1 TP3 Conductor/Performer refinement 4.2.1 TP4 Interpreted, remixed, or otherwise modified by 4.2.1 TPA Part of a set 4.2.1 TPB Publisher 4.2.1 TRC ISRC (International Standard Recording Code) 4.2.1 TRD Recording dates 4.2.1 TRK Track number/Position in set 4.2.1 TSI Size 4.2.1 TSS Software/hardware and settings used for encoding 4.2.1 TT1 Content group description 4.2.1 TT2 Title/Songname/Content description 4.2.1 TT3 Subtitle/Description refinement 4.2.1 TXT Lyricist/text writer 4.2.2 TXX User defined text information frame 4.2.1 TYE Year 4.1 UFI Unique file identifier 4.9 ULT Unsychronized lyric/text transcription 4.3.1 WAF Official audio file webpage 4.3.1 WAR Official artist/performer webpage 4.3.1 WAS Official audio source webpage 4.3.1 WCM Commercial information 4.3.1 WCP Copyright/Legal information 4.3.1 WPB Publishers official webpage 4.3.2 WXX 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 contain more information relevant to the content. Since standardisation of such a database is beyond this document, all frames begin with 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. If a $00 is found directly after the 'Frame size' the whole frame should be ignored, and preferably be removed. The 'Owner identifier' is then followed by the actual identifier, which may be up to 64 bytes. There may be more than one "UFI" frame in a tag, but only one with the same 'Owner identifier'. Unique file identifier "UFI" Frame size $xx xx xx Owner identifier <textstring> $00 Identifier <up to 64 bytes binary data> 4.2. Text information frames The text information frames are 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. If the textstring is followed by a termination ($00 (00)) all the following information should be ignored and not be displayed. All the text information frames have the following format: Text information identifier "T00" - "TZZ" , excluding "TXX", described in 4.2.2. Frame size $xx xx xx Text encoding $xx Information <textstring> 4.2.1. Text information frames - details TT1 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"). TT2 The 'Title/Songname/Content description' frame is the actual name of the piece (e.g. "Adagio", "Hurricane Donna"). TT3 The 'Subtitle/Description refinement' frame is used for information directly related to the contents title (e.g. "Op. 16" or "Performed live at wembley"). TP1 The 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group' is used for the main artist(s). They are seperated with the "/" character. TP2 The 'Band/Orchestra/Accompaniment' frame is used for additional information about the performers in the recording. TP3 The 'Conductor' frame is used for the name of the conductor. TP4 The 'Interpreted, remixed, or otherwise modified by' frame contains more information about the people behind a remix and similar interpretations of another existing piece. TCM The 'Composer(s)' frame is intended for the name of the composer(s). They are seperated with the "/" character. TXT The 'Lyricist(s)/text writer(s)' frame is intended for the writer(s) of the text or lyrics in the recording. They are seperated with the "/" character. TLA The 'Language(s)' frame should contain the languages of the text or lyrics in the audio file. The language is represented with three characters according to ISO-639-2. If more than one language is used in the text their language codes should follow according to their usage. TCO The content type, which previously (in ID3v1.1, see appendix A) was stored as a one byte numeric value only, is now a numeric string. You may use one or several of the types as ID3v1.1 did or, since the category list would be impossible to maintain with accurate and up to date categories, define your own. References to the ID3v1 genres can be made by, as first byte, enter "(" followed by a number from the genres list (section A.3.) and ended with a ")" character. This is optionally followed by a refinement, e.g. "(21)" or "(4)Eurodisco". Several references can be made in the same frame, e.g. "(51)(39)". If the refinement should begin with a "(" character it should be replaced with "((", e.g. "((I can figure out any genre)" or "(55)((I think...)". The following new content types is defined in ID3v2 and is implemented in the same way as the numerig content types, e.g. "(RX)". RX Remix CR Cover TAL The 'Album/Movie/Show title' frame is intended for the title of the recording(/source of sound) which the audio in the file is taken from. TPA 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 "TAL" 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". TRK 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 numer of tracks/elements on the original recording. E.g. "4/9". TRC The 'ISRC' frame should contian the International Standard Recording Code [ISRC]. TYE The 'Year' frame is a numeric string with a year of the recording. This frames is always four characters long (until the year 10000). TDA The 'Date' frame is a numeric string in the DDMM format containing the date for the recording. This field is always four characters long. TIM The 'Time' frame is a numeric string in the HHMM format containing the time for the recording. This field is always four characters long. TRD The 'Recording dates' frame is a intended to be used as complement to the "TYE", "TDA" and "TIM" frames. E.g. "4th-7th June, 12th June" in combination with the "TYE" frame. TMT The 'Media type' frame describes from which media the sound originated. This may be a textstring or a reference to the predefined media types found in the list below. References are made within "(" and ")" and are optionally followed by a text refinement, e.g. "(MC) with four channels". If a text refinement should begin with a "(" character it should be replaced with "((" in the same way as in the "TCO" frame. Predefined refinements is appended after the media type, e.g. "(CD/S)" or "(VID/PAL/VHS)". DIG Other digital media /A Analog transfer from media ANA Other analog media /WAC Wax cylinder /8CA 8-track tape cassette CD CD /A Analog transfer from media /DD DDD /AD ADD /AA AAD LD Laserdisc /A Analog transfer from media 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 Analog transfer from media DAT DAT /A Analog 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, nonlinear, 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 Analog transfer from media DVD DVD /A Analog 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) TFT The 'File type' frame indicates which type of audio this tag defines. The following type and refinements are defined: MPG MPEG Audio /1 MPEG 2 layer I /2 MPEG 2 layer II /3 MPEG 2 layer III /2.5 MPEG 2.5 /AAC Advanced audio compression but other types may be used, not for these types though. This is used in a similar way to the predefined types in the "TMT" frame, but without parenthesis. If this frame is not present audio type is assumed to be "MPG". TBP BPM is short for beats per minute, and is easily computed by dividing the number of beats in a musical piece with its length. To get a more accurate result, do the BPM calculation on the main-part only. To acquire best result measure the time between each beat and calculate individual BPM for each beat and use the median value as result. BPM is an integer and represented as a numerical string. TCR The 'Copyright message' frame, which 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 sound 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. TPB The 'Publisher' frame simply contains the name of the label or publisher. TEN 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. TSS 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. TOF 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. TLE The 'Length' frame contains the length of the audiofile in milliseconds, represented as a numeric string. TSI The 'Size' frame contains the size of the audiofile in bytes excluding the tag, represented as a numeric string. TDY The 'Playlist delay' defines the numbers of milliseconds of silence between every song in a playlist. The player should use the "ETC" frame, if present, to skip initial silence and silence at the end of the audio to match the 'Playlist delay' time. The time is represented as a numeric string. TKE 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". Example "Cbm". Off key is represented with an "o" only. TOT The 'Original album/Movie/Show title' frame is intended for the title of the original recording(/source of sound), if for example the music in the file should be a cover of a previously released song. TOA The 'Original artist(s)/performer(s)' frame is intended for the performer(s) of the original recording, if for example the music in the file should be a cover of a previously released song. The performers are seperated with the "/" character. TOL The 'Original Lyricist(s)/text writer(s)' frame is intended for the text writer(s) of the original recording, if for example the music in the file should be a cover of a previously released song. The text writers are seperated with the "/" character. TOR The 'Original release year' frame is intended for the year when the original recording, if for example the music in the file should be a cover of a previously released song, was released. The field is formatted as in the "TDY" frame. 4.2.2. User defined text information frame This frame is intended for one-string text information concerning the audiofile in a similar way to the other "T"xx 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 "TXX" frame in each tag, but only one with the same description. User defined... "TXX" Frame size $xx xx xx Text encoding $xx Description <textstring> $00 (00) Value <textstring> 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 textstring is followed by a termination ($00 (00)) all the following information should be ignored and not be displayed. All URL link frames have the following format: URL link frame "W00" - "WZZ" , excluding "WXX" (described in 4.3.2.) Frame size $xx xx xx URL <textstring> 4.3.1. URL link frames - details WAF The 'Official audio file webpage' frame is a URL pointing at a file specific webpage. WAR The 'Official artist/performer webpage' frame is a URL pointing at the artists official webpage. There may be more than one "WAR" frame in a tag if the audio contains more than one performer. WAS 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. WCM 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 "WCM" frame in a tag. WCP The 'Copyright/Legal information' frame is a URL pointing at a webpage where the terms of use and ownership of the file is described. WPB The 'Publishers official webpage' frame is a URL pointing at the official wepage for the publisher. 4.3.2. User defined URL link frame This frame is intended for URL [URL] links concerning the audiofile in a similar way to the other "W"xx 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 "WXX" frame in each tag, but only one with the same description. User defined... "WXX" Frame size $xx xx xx Text encoding $xx Description <textstring> $00 (00) URL <textstring> 4.4. Involved people list Since there might be a lot of people contributing to an audio file in various ways, such as musicians and technicians, the 'Text information frames' are often insufficient to list everyone involved in a project. The 'Involved people list' is a frame containing the names of those involved, and how they were involved. The body simply contains a terminated string with the involvement directly followed by a terminated string with the involvee followed by a new involvement and so on. There may only be one "IPL" frame in each tag. Involved people list "IPL" Frame size $xx xx xx Text encoding $xx People list strings <textstrings> 4.5. 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 making a maximum of 804 bytes. This frame requires a present and valid "TRK" frame. There may only be one "MCI" frame in each tag. Music CD identifier "MCI" Frame size $xx xx xx CD TOC <binary data> 4.6. Event timing codes This frame allows synchronisation with key events in a song or sound. The head is: Event timing codes "ETC" Frame size $xx xx xx 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 Abolute 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 should 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 mainpart start $04 outro start $05 outro end $06 verse begins $07 refrain begins $08 interlude $09 theme start $0A variation $0B key change $0C time change $0D unwanted noise (Snap, Crackle & Pop) $0E-$DF reserved for future use $E0-$EF not predefined sync 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) The 'Not predefined sync's ($E0-EF) are for user events. You might want to synchronise your music to something, like setting of an explosion on-stage, turning on your screensaver etc. There may only be one "ETC" frame in each tag. 4.7. MPEG location lookup table To increase performance and accuracy of jumps within a MPEG [MPEG] audio file, frames with timecodes in different locations in the file might be useful. The ID3 frame includes references that the software can use to calculate positions in the file. After the frame header is a descriptor of how much the 'frame counter' should increase 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 "MLL" frame in each tag. Location lookup table "MLL" ID3 frame size $xx xx xx 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.8. Synced 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 should 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 "STC" frame in each tag. Synced tempo codes "STC" Frame size $xx xx xx Time stamp format $xx Tempo data <binary 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 Abolute time means that every stamp contains the time from the beginning of the file. 4.9. Unsychronised 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. Maximum length for the descriptor is 64 bytes. There may be more than one lyrics/text frame in each tag, but only one with the same language and content descriptor. Unsynced lyrics/text "ULT" Frame size $xx xx xx Text encoding $xx Language $xx xx xx Content descriptor <textstring> $00 (00) Lyrics/text <textstring> 4.10. 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 textstring. If no descriptor is entered, 'Content descriptor' is $00 (00) only. Synced lyrics/text "SLT" Frame size $xx xx xx Text encoding $xx Language $xx xx xx Time stamp format $xx Content type $xx Content descriptor <textstring> $00 (00) Encoding: $00 ISO-8859-1 [ISO-8859-1] character set is used => $00 is sync identifier. $01 Unicode [UNICODE] character set is used => $00 00 is sync identifier. 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") 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 Abolute 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 "SLT" frames and should 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 "ULT" passage "Strangers in the night" $0A "Exchanging glances" would be "SLT" 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 "SLT" frame in each tag, but only one with the same language and content descriptor. 4.11. Comments This frame replaces the old 30-character comment field in ID3v1. It consists of a frame head 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. Comment "COM" Frame size $xx xx xx Text encoding $xx Language $xx xx xx Short content description <textstring> $00 (00) The actual text <textstring> 4.12. Relative volume adjustment This is a more subjective function than the previous ones. It allows the user to say how much he wants to increase/decrease the volume on each channel while 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. If the volume peak levels are known then this could be described with the 'Peak volume right' and 'Peak volume left' field. If Peakvolume is not known these fields could be left zeroed or completely omitted. There may only be one "RVA" frame in each tag. Relative volume adjustment "RVA" Frame size $xx xx xx Increment/decrement %000000xx Bits used for volume descr. $xx Relative volume change, right $xx xx (xx ...) Relative volume change, left $xx xx (xx ...) Peak volume right $xx xx (xx ...) Peak volume left $xx xx (xx ...) In the increment/decrement field bit 0 is used to indicate the right channel and bit 1 is used to indicate the left channel. 1 is increment and 0 is decrement. The 'bits used for volume description' field is normally $10 (16 bits) for MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value may not be $00. The volume is always represented with whole bytes, padded in the beginning (highest bits) when 'bits used for volume description' is not a multiple of eight. 4.13. Equalisation This is another subjective, alignment frame. It allows the user to predefine an equalisation curve within the audio file. There may only be one "EQU" frame in each tag. Equalisation "EQU" Frame size $xx xx xx Adjustment bits $xx The 'adjustment bits' field defines the number of bits used for representation of the adjustment. This is normally $10 (16 bits) for MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value may not be $00. This is followed by 2 bytes + ('adjustment bits' rounded up to the nearest byte) for every equalisation band in the following format, giving a frequency range of 0 - 32767Hz: Increment/decrement %x (MSB of the Frequency) Frequency (lower 15 bits) Adjustment $xx (xx ...) The increment/decrement bit is 1 for increment and 0 for decrement. The equalisation bands should be ordered increasingly with reference to frequency. All frequencies don't have to be declared. Adjustments with the value $00 should be omitted. A frequency should only be described once in the frame. 4.14. Reverb Yet another subjective one. You may here 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, yet 50% 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 "REV" frame in each tag. Reverb settings "REV" Frame size $00 00 0C 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.15. Attached picture This frame contains a picture directly related to the audio file. Image format is preferably "PNG" [PNG] or "JPG" [JFIF]. Description is a short description of the picture, represented as a terminated textstring. The description has a maximum length of 64 characters, but may be empty. There may be several pictures attached to one file, each in their individual "PIC" 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 a possibility to put only a link to the image file by using the 'image format' "-->" and having a complete URL [URL] instead of picture data. The use of linked files should however be used restrictively since there is the risk of separation of files. Attached picture "PIC" Frame size $xx xx xx Text encoding $xx Image format $xx xx xx Picture type $xx Description <textstring> $00 (00) Picture data <binary 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. lable 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.16. General encapsulated object In this frame any type of file can be encapsulated. After the header, 'Frame size' and 'Encoding' follows 'MIME type' [MIME] and 'Filename' for the encapsulated object, both represented as terminated strings encoded with ISO 8859-1 [ISO-8859-1]. The filename is case sensitive. 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 "GEO" frame in each tag, but only one with the same content descriptor. General encapsulated object "GEO" Frame size $xx xx xx Text encoding $xx MIME type <textstring> $00 Filename <textstring> $00 (00) Content description <textstring> $00 (00) Encapsulated object <binary data> 4.17. 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 "CNT" 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. Play counter "CNT" Frame size $xx xx xx Counter $xx xx xx xx (xx ...) 4.18. 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 audiofiles more often than others or it could be used to profile a persons taste and find other 'good' files by comparing people's profiles. The frame is very simple. It 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 ("CNT"). There may be more than one "POP" frame in each tag, but only one with the same email address. Popularimeter "POP" Frame size $xx xx xx Email to user <textstring> $00 Rating $xx Counter $xx xx xx xx (xx ...) 4.19. Recommended buffer size Sometimes the server from which a 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 audiostream. 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 is currently not recommended since this could render unpredictable behaviour from present software/hardware. The 'Buffer size' should be kept to a minimum. There may only be one "BUF" frame in each tag. Recommended buffer size "BUF" Frame size $xx xx xx Buffer size $xx xx xx Embedded info flag %0000000x Offset to next tag $xx xx xx xx 4.20. Encrypted meta frame This frame contains one or more encrypted frames. This enables protection of copyrighted information such as pictures and text, that people might want to pay extra for. Since standardisation of such an encryption scheme is beyond this document, all "CRM" frames begin with a terminated string with a URL [URL] containing an email address, or a link to a location where an email adress can be found, that belongs to the organisation responsible for this specific encrypted meta frame. Questions regarding the encrypted frame should be sent to the indicated email address. If a $00 is found directly after the 'Frame size', the whole frame should be ignored, and preferably be removed. The 'Owner identifier' is then followed by a short content description and explanation as to why it's encrypted. After the 'content/explanation' description, the actual encrypted block follows. When an ID3v2 decoder encounters a "CRM" frame, it should send the datablock to the 'plugin' with the corresponding 'owner identifier' and expect to receive either a datablock with one or several ID3v2 frames after each other or an error. There may be more than one "CRM" frames in a tag, but only one with the same 'owner identifier'. Encrypted meta frame "CRM" Frame size $xx xx xx Owner identifier <textstring> $00 (00) Content/explanation <textstring> $00 (00) Encrypted datablock <binary data> 4.21. Audio encryption This frame indicates if the actual audio stream is encrypted, and by whom. Since standardisation of such encrypion scheme is beyond this document, all "CRA" 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 audiofile 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 datablock required for decryption of the audio. There may be more than one "CRA" frames in a tag, but only one with the same 'Owner identifier'. Audio encryption "CRA" Frame size $xx xx xx Owner identifier <textstring> $00 (00) Preview start $xx xx Preview length $xx xx Encryption info <binary data> 4.22. Linked information To keep space waste 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 seperation 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 "LNK" 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 "REV" frame allowed, whether it's linked or not). Linked information "LNK" Frame size $xx xx xx Frame identifier $xx xx xx URL <textstring> $00 (00) Additional ID data <textstring(s)> Frames that may be linked and need no additional data are "IPL", "MCI", "ETC", "LLT", "STC", "RVA", "EQU", "REV", "BUF", the text information frames and the URL link frames. The "TXX", "PIC", "GEO", "CRM" and "CRA" frames may be linked with the content descriptor as additional ID data. The "COM", "SLT" and "ULT" frames may be linked with three bytes of language descriptor directly followed by a content descriptor as additional ID data. 5. The 'unsynchronisation scheme' The only purpose of the 'unsychronisation scheme' is to make the ID3v2 tag as compatible as possible with existing software. There is no use in 'unsynchronising' tags if the file is only to be processed by new software. Unsynchronisation may only be made with MPEG 2 layer I, II and III and MPEG 2.5 files. Whenever a false synchronisation is found within the tag, one zeroed byte is inserted after the first false synchronisation byte. The format of a correct sync 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 won't be affected by the decoding process. Therefore all the $FF 00 combinations have to be replaced with the $FF 00 00 combination during the unsynchonisation. To indicate usage of the unsynchronisation, the first bit in 'ID3 flags' should be set. This bit should only be set if the tag contained a, now corrected, false synchronisation. The bit should only be clear if the tag does not contain any false synchronisations. Do bear in mind, that if a compression scheme is used by the encoder, the unsyncronisation scheme should be applied *afterwards*. When decoding a compressed, 'unsyncronised' file, the 'unsyncronisation scheme' should be parsed first, compression afterwards. 6. Copyright Copyright (C) Martin Nilsson 1998. 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. 7. References [CDDB] Compact Disc Data Base <url:http://www.cddb.com> [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-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 <url:http://www.w3.org/Graphics/JPEG/jfif.txt> [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996. <url:ftp://ftp.isi.edu/in-notes/rfc2045.txt> [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:http://www.w3.org/TR/REC-png-multi.html> [UNICODE] ISO/IEC 10646-1:1993. Universal Multiple-Octet Coded Character Set (UCS), Part 1: Architecture and Basic Multilingual Plane. Technical committee / subcommittee: JTC 1 / SC 2 <url:http://www.unicode.org> [URL] T. Berners-Lee, L. Masinter & M. McCahill, "Uniform Resource Locators (URL).", RFC 1738, December 1994. <url:ftp://ftp.isi.edu/in-notes/rfc1738.txt> 8. Appendix A. Appendix A - ID3-Tag Specification V1.1 ID3-Tag Specification V1.1 (12 dec 1997) by Michael Mutschler <amiga2@info2.rus.uni-stuttgart.de>, edited for space and clarity reasons. A.1. Overview The ID3-Tag is an information field for MPEG Layer 3 audio files. Since a standalone MP3 doesn't provide a method of storing other information than those directly needed for replay reasons, the ID3-tag was invented by Eric Kemp in 1996. A revision from ID3v1 to ID3v1.1 was made by Michael Mutschler to support track number information is described in A.4. A.2. ID3v1 Implementation The Information is stored in the last 128 bytes of an MP3. The Tag has got the following fields, and the offsets given here, are from 0-127. Field Length Offsets Tag 3 0-2 Songname 30 3-32 Artist 30 33-62 Album 30 63-92 Year 4 93-96 Comment 30 97-126 Genre 1 127 The string-fields contain ASCII-data, coded in ISO-Latin 1 codepage. Strings which are smaller than the field length are padded with zero- bytes. Tag: The tag is valid if this field contains the string "TAG". This has to be uppercase! Songname: This field contains the title of the MP3 (string as above). Artist: This field contains the artist of the MP3 (string as above). Album: this field contains the album where the MP3 comes from (string as above). Year: this field contains the year when this song has originally been released (string as above). Comment: this field contains a comment for the MP3 (string as above). Revision to this field has been made in ID3v1.1. See A.4. Genre: this byte contains the offset of a genre in a predefined list the byte is treated as an unsigned byte. The offset is starting from 0. See A.3. A.3. Genre List 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 The following genres are Winamp extensions 80.Folk 81.Folk-Rock 82.National Folk 83.Swing 84.Fast Fusion 85.Bebob 86.Latin 87.Revival 88.Celtic 89.Bluegrass 90.Avantgarde 91.Gothic Rock 92.Progressive Rock 93.Psychedelic Rock 94.Symphonic Rock 95.Slow Rock 96.Big Band 97.Chorus 98.Easy Listening 99.Acoustic 100.Humour 101.Speech 102.Chanson 103.Opera 104.Chamber Music 105.Sonata 106.Symphony 107.Booty Bass 108.Primus 109.Porn Groove 110.Satire 111.Slow Jam 112.Club 113.Tango 114.Samba 115.Folklore 116.Ballad 117.Power Ballad 118.Rhythmic Soul 119.Freestyle 120.Duet 121.Punk Rock 122.Drum Solo 123.A capella 124.Euro-House 125.Dance Hall A.4. Track addition - ID3v1.1 In ID3v1.1, Michael Mutschler revised the specification of the comment field in order to implement the track number. The new format of the comment field is a 28 character string followed by a mandatory null ($00) character and the original album tracknumber stored as an unsigned byte-size integer. In such cases where the 29th byte is not the null character or when the 30th is a null character, the tracknumber is to be considered undefined. 9. Author's Address Martin Nilsson Rydsvgen 246 C. 30 S-584 34 Linkping Sweden Email: nilsson@id3.org Co-authors: Johan Sundstrm Email: johan@id3.org �����������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2.3.0.txt��������������������������������������������������������0000664�0000000�0000000�00000226714�12225024651�0020107�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Informal standard M. Nilsson Document: id3v2.3.0.txt 3rd February 1999 ID3 tag version 2.3.0 Status of this document This document is an informal standard and replaces the ID3v2.2.0 standard [ID3v2]. The informal standard is released so that implementors could have a set standard before a formal standard is set. The formal standard will use another version or revision number if not identical to what is described in this 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 ID3v2.3.0, which is a more developed version of the ID3v2 informal standard [ID3v2] (version 2.2.0), evolved from the ID3 tagging system. The ID3v2 offers a flexible way of storing information about an audio file within itself to determine its origin and contents. The information may be technical information, such as equalisation curves, as well as related meta information, such as title, performer, copyright etc. 1. Table of contents 2. Conventions in this document 3. ID3v2 overview 3.1. ID3v2 header 3.2. ID3v2 extended header 3.3. ID3v2 frames overview 3.3.1. Frame header flags 3.3.2. Default flags 4. Declared ID3v2 frames 4.1. Unique file identifier 4.2. Text information frames 4.2.1. Text information frames - details 4.2.2. 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. Involved people list 4.5. Music CD Identifier 4.6. Event timing codes 4.7. MPEG location lookup table 4.8. Synced tempo codes 4.9. Unsychronised lyrics/text transcription 4.10. Synchronised lyrics/text 4.11. Comments 4.12. Relative volume adjustment 4.13. Equalisation 4.14. Reverb 4.15. Attached picture 4.16. General encapsulated object 4.17. Play counter 4.18. Popularimeter 4.19. Recommended buffer size 4.20. Audio encryption 4.21. Linked information 4.22. Position synchronisation frame 4.23. Terms of use 4.24. Ownership frame 4.25. Commercial frame 4.26. Encryption method registration 4.27. Group identification registration 4.28. Private frame 5. The 'unsynchronisation scheme' 6. Copyright 7. References 8. Appendix A. Appendix A - Genre List from ID3v1 9. Author's Address 2. Conventions in this document In the examples, text within "" is a text string exactly as it appears in a file. 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 0-9 only. 3. ID3v2 overview The two biggest design goals were to be able to implement ID3v2 without disturbing old software too much and that ID3v2 should be as flexible and expandable as possible. The first criterion is met by the simple fact that the MPEG [MPEG] decoding software uses a syncsignal, embedded in the audiostream, to 'lock on to' the audio. Since the ID3v2 tag doesn't contain a valid syncsignal, no software will attempt to play the tag. If, for any reason, coincidence make a syncsignal appear within the tag it will be taken care of by the 'unsynchronisation scheme' described in section 5. The second criterion has made a more noticeable impact on the design of the ID3v2 tag. It 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 there is an identifier that explains the frames' format and content, and a size descriptor that allows software to skip unknown frames. If a total revision of the ID3v2 tag should be needed, there is a version number and a size descriptor in the ID3v2 header. 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. 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). It is permitted to include padding after all 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 head of the tag. 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. 3.1. ID3v2 header The ID3v2 tag header, which should be the first information in the file, is 10 bytes as follows: ID3v2/file identifier "ID3" ID3v2 version $03 00 ID3v2 flags %abc00000 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 it's major version, while the second byte is its revision number. In this case this is ID3v2.3.0. All revisions are backwards compatible while major versions are not. If software with ID3v2.2.0 and below support should encounter version three or higher it should simply ignore the whole tag. Version and revision will never be $FF. The version is followed by one the ID3v2 flags field, of which currently only three flags are used. a - Unsynchronisation Bit 7 in the 'ID3v2 flags' indicates whether or not unsynchronisation is used (see section 5 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. c - Experimental indicator The third bit (bit 5) should be used as an 'experimental indicator'. This flag should always be set when the tag is in an experimental stage. All the other flags should be cleared. If one of these undefined flags are set that might mean that the tag is not readable for a parser that does not know the flags function. The ID3v2 tag size is encoded with four bytes where the most significant bit (bit 7) is set to zero in every byte, making a total of 28 bits. The zeroed bits are ignored, so a 257 bytes long tag is represented as $00 00 02 01. The ID3v2 tag size is the size of the complete tag after unsychronisation, including padding, excluding the header but not excluding the extended header (total tag size - 10). Only 28 bits (representing up to 256MB) are used in the size description to avoid the introducuction of 'false syncsignals'. 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. ID3v2 extended header The extended header contains information that is not vital to the correct parsing of the tag information, hence the extended header is optional. Extended header size $xx xx xx xx Extended Flags $xx xx Size of padding $xx xx xx xx Where the 'Extended header size', currently 6 or 10 bytes, excludes itself. The 'Size of padding' is simply the total tag size excluding the frames and the headers, in other words the padding. The extended header is considered separate from the header proper, and as such is subject to unsynchronisation. The extended flags are a secondary flag set which describes further attributes of the tag. These attributes are currently defined as follows %x0000000 00000000 x - CRC data present If this flag is set four bytes of CRC-32 data is appended to the extended header. The CRC should be calculated before unsynchronisation on the data between the extended header and the padding, i.e. the frames and only the frames. Total frame CRC $xx xx xx xx 3.3. ID3v2 frame overview As the tag consists of a tag header and a tag body with one or more frames, all the frames consists of a frame header followed by one or more fields containing the actual information. The layout of the frame header: Frame ID $xx xx xx xx (four characters) Size $xx xx xx xx Flags $xx xx The frame ID made out of the characters capital A-Z and 0-9. Identifiers beginning with "X", "Y" and "Z" are for experimental use and free for everyone to use, without the need to set the experimental bit in the tag header. Have 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, making a total header size of ten bytes in every frame. The size is calculated as frame size excluding frame header (frame size - 10). In the frame header the size descriptor is followed by two flags bytes. These flags are described in section 3.3.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 a string is represented as ISO-8859-1 [ISO-8859-1] characters in the range $20 - $FF. Such strings are represented as <text string>, or <full text string> if newlines are allowed, in the frame descriptions. All Unicode strings [UNICODE] use 16-bit unicode 2.0 (ISO/IEC 10646-1:1993, UCS-2). Unicode strings must begin with the Unicode BOM ($FF FE or $FE FF) to identify the byte order. All numeric strings and URLs [URL] are always encoded as ISO-8859-1. Terminated strings are terminated with $00 if encoded with ISO-8859-1 and $00 00 if encoded as unicode. If nothing else is said newline character is forbidden. In ISO-8859-1 a new line is represented, when allowed, with $0A only. Frames that allow different types of text encoding have a text encoding description byte directly after the frame size. If ISO-8859-1 is used this byte should be $00, if Unicode is used it should be $01. Strings dependent on encoding is represented as <text string according to encoding>, or <full text string according to encoding> if newlines are allowed. Any empty Unicode strings which are NULL-terminated may have the Unicode BOM followed by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00). The three byte language field is used to describe the language of the frame's content, according to ISO-639-2 [ISO-639-2]. 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. 3.3.1. Frame header flags In the frame header the size descriptor is followed by two flags bytes. All unused flags must be cleared. The first byte is for 'status messages' and the second byte is for encoding purposes. If an unknown flag is set in the first byte the frame may not be changed without the bit cleared. If an unknown flag is set in the second byte it is likely to not be readable. The flags field is defined as follows. %abc00000 %ijk00000 a - Tag alter preservation This flag tells the software 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 software 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 is intended to be read only. Changing the contents might break something, e.g. a signature. If the contents are changed, without knowledge in why the frame was flagged read only and without taking the proper means to compensate, e.g. recalculating the signature, the bit should be cleared. i - Compression This flag indicates whether or not the frame is compressed. 0 Frame is not compressed. 1 Frame is compressed using zlib [zlib] with 4 bytes for 'decompressed size' appended to the frame header. j - Encryption This flag indicates wether or not the frame is enrypted. If set one byte indicating with which method it was encrypted will be appended to the frame header. See section 4.26. for more information about encryption method registration. 0 Frame is not encrypted. 1 Frame is encrypted. k - 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 header. Every frame with the same group identifier belongs to the same group. 0 Frame does not contain group information 1 Frame contains group information Some flags indicates that the frame header is extended with additional information. This information will be added to the frame header in the same order as the flags indicating the additions. I.e. the four bytes of decompressed size will preceed the encryption method byte. These additions to the frame header, while not included in the frame header size but are included in the 'frame size' field, are not subject to encryption or compression. 3.3.2. 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. AENC, ETCO, EQUA, MLLT, POSS, SYLT, SYTC, RVAD, TENC, TLEN, TSIZ 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.21 AENC Audio encryption 4.15 APIC Attached picture 4.11 COMM Comments 4.25 COMR Commercial frame 4.26 ENCR Encryption method registration 4.13 EQUA Equalization 4.6 ETCO Event timing codes 4.16 GEOB General encapsulated object 4.27 GRID Group identification registration 4.4 IPLS Involved people list 4.21 LINK Linked information 4.5 MCDI Music CD identifier 4.7 MLLT MPEG location lookup table 4.24 OWNE Ownership frame 4.28. PRIV Private frame 4.17 PCNT Play counter 4.18 POPM Popularimeter 4.22 POSS Position synchronisation frame 4.19 RBUF Recommended buffer size 4.12 RVAD Relative volume adjustment 4.14 RVRB Reverb 4.10 SYLT Synchronized lyric/text 4.8 SYTC Synchronized tempo codes 4.2.1 TALB Album/Movie/Show title 4.2.1 TBPM BPM (beats per minute) 4.2.1 TCOM Composer 4.2.1 TCON Content type 4.2.1 TCOP Copyright message 4.2.1 TDAT Date 4.2.1 TDLY Playlist delay 4.2.1 TENC Encoded by 4.2.1 TEXT Lyricist/Text writer 4.2.1 TFLT File type 4.2.1 TIME Time 4.2.1 TIT1 Content group description 4.2.1 TIT2 Title/songname/content description 4.2.1 TIT3 Subtitle/Description refinement 4.2.1 TKEY Initial key 4.2.1 TLAN Language(s) 4.2.1 TLEN Length 4.2.1 TMED Media type 4.2.1 TOAL Original album/movie/show title 4.2.1 TOFN Original filename 4.2.1 TOLY Original lyricist(s)/text writer(s) 4.2.1 TOPE Original artist(s)/performer(s) 4.2.1 TORY Original release year 4.2.1 TOWN File owner/licensee 4.2.1 TPE1 Lead performer(s)/Soloist(s) 4.2.1 TPE2 Band/orchestra/accompaniment 4.2.1 TPE3 Conductor/performer refinement 4.2.1 TPE4 Interpreted, remixed, or otherwise modified by 4.2.1 TPOS Part of a set 4.2.1 TPUB Publisher 4.2.1 TRCK Track number/Position in set 4.2.1 TRDA Recording dates 4.2.1 TRSN Internet radio station name 4.2.1 TRSO Internet radio station owner 4.2.1 TSIZ Size 4.2.1 TSRC ISRC (international standard recording code) 4.2.1 TSSE Software/Hardware and settings used for encoding 4.2.1 TYER Year 4.2.2 TXXX User defined text information frame 4.1 UFID Unique file identifier 4.23 USER Terms of use 4.9 USLT Unsychronized 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 contain more information relevant to the content. Since standardisation of such a database is beyond this document, all frames begin with 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 "<a href="http://www.id3.org/dummy/ufid.html">http://www.id3.org/dummy/ufid.html</a>" should be used for tests. Software that isn't told otherwise may safely remove such frames. 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'. <Header for 'Unique file identifier', ID: "UFID"> Owner identifier <text string> $00 Identifier <up to 64 bytes binary data> 4.2. Text information frames The text information frames are 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. If the textstring is followed by a termination ($00 (00)) all the following information should be ignored and not be displayed. 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: <Header for 'Text information frame', ID: "T000" - "TZZZ", excluding "TXXX" described in 4.2.2.> Text encoding $xx Information <text string according to encoding> 4.2.1. Text information frames - details TALB The 'Album/Movie/Show title' frame is intended for the title of the recording(/source of sound) which the audio in the file is taken from. TBPM The 'BPM' frame contains the number of beats per minute in the mainpart of the audio. The BPM is an integer and represented as a numerical string. TCOM The 'Composer(s)' frame is intended for the name of the composer(s). They are seperated with the "/" character. TCON The 'Content type', which previously was stored as a one byte numeric value only, is now a numeric string. You may use one or several of the types as ID3v1.1 did or, since the category list would be impossible to maintain with accurate and up to date categories, define your own. References to the ID3v1 genres can be made by, as first byte, enter "(" followed by a number from the genres list (appendix A.) and ended with a ")" character. This is optionally followed by a refinement, e.g. "(21)" or "(4)Eurodisco". Several references can be made in the same frame, e.g. "(51)(39)". If the refinement should begin with a "(" character it should be replaced with "((", e.g. "((I can figure out any genre)" or "(55)((I think...)". The following new content types is defined in ID3v2 and is implemented in the same way as the numerig content types, e.g. "(RX)". RX Remix CR Cover TCOP The 'Copyright message' frame, which 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 sound 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. TDAT The 'Date' frame is a numeric string in the DDMM format containing the date for the recording. This field is always four characters long. TDLY The 'Playlist delay' defines the numbers of milliseconds of silence between every song in a playlist. The player should use the "ETC" frame, if present, to skip initial silence and silence at the end of the audio to match the 'Playlist delay' time. The time is represented as a numeric string. 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. TEXT The 'Lyricist(s)/Text writer(s)' frame is intended for the writer(s) of the text or lyrics in the recording. They are seperated with the "/" character. TFLT The 'File type' frame indicates which type of audio this tag defines. The following type and refinements are defined: 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 Quantization PCM Pulse Code Modulated audio but other types may be used, 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". TIME The 'Time' frame is a numeric string in the HHMM format containing the time for the recording. This field is always four characters long. 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"). 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". Example "Cbm". Off key is represented with an "o" only. TLAN The 'Language(s)' 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. If more than one language is used in the text their language codes should follow according to their usage. TLEN The 'Length' frame contains the length of the audiofile in milliseconds, represented as a numeric string. 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. References are made within "(" and ")" and are optionally followed by a text refinement, e.g. "(MC) with four channels". If a text refinement should begin with a "(" character it should be replaced with "((" in the same way as in the "TCO" frame. Predefined refinements is appended after the media type, e.g. "(CD/A)" or "(VID/PAL/VHS)". DIG Other digital media /A Analog transfer from media ANA Other analog media /WAC Wax cylinder /8CA 8-track tape cassette CD CD /A Analog transfer from media /DD DDD /AD ADD /AA AAD LD Laserdisc /A Analog transfer from media 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 Analog transfer from media DAT DAT /A Analog 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, nonlinear, 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 Analog transfer from media DVD DVD /A Analog 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) 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. 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. TOLY The 'Original lyricist(s)/text writer(s)' frame is intended for the text writer(s) of the original recording, if for example the music in the file should be a cover of a previously released song. The text writers are seperated with the "/" character. TOPE The 'Original artist(s)/performer(s)' frame is intended for the performer(s) of the original recording, if for example the music in the file should be a cover of a previously released song. The performers are seperated with the "/" character. TORY The 'Original release year' frame is intended for the year when the original recording, if for example the music in the file should be a cover of a previously released song, was released. The field is formatted as in the "TYER" frame. TOWN The 'File owner/licensee' frame contains the name of the owner or licensee of the file and it's contents. TPE1 The 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group' is used for the main artist(s). They are seperated with the "/" character. 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. 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". TPUB The 'Publisher' frame simply contains the name of the label or publisher. 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 numer of tracks/elements on the original recording. E.g. "4/9". TRDA The 'Recording dates' frame is a intended to be used as complement to the "TYER", "TDAT" and "TIME" frames. E.g. "4th-7th June, 12th June" in combination with the "TYER" frame. 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. TSIZ The 'Size' frame contains the size of the audiofile in bytes, excluding the ID3v2 tag, represented as a numeric string. TSRC The 'ISRC' frame should contain the International Standard Recording Code [ISRC] (12 characters). 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. TYER The 'Year' frame is a numeric string with a year of the recording. This frames is always four characters long (until the year 10000). 4.2.2. User defined text information frame This frame is intended for one-string text information concerning the audiofile 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. <Header for 'User defined text information frame', ID: "TXXX"> Text encoding $xx Description <text string according to encoding> $00 (00) Value <text string according to encoding> 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 textstring is followed by a termination ($00 (00)) 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". All URL link frames have the following format: <Header for 'URL link frame', ID: "W000" - "WZZZ", excluding "WXXX" described in 4.3.2.> URL <text string> 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 wepage for the publisher. 4.3.2. User defined URL link frame This frame is intended for URL [URL] links concerning the audiofile 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. <Header for 'User defined URL link frame', ID: "WXXX"> Text encoding $xx Description <text string according to encoding> $00 (00) URL <text string> 4.4. Involved people list Since there might be a lot of people contributing to an audio file in various ways, such as musicians and technicians, the 'Text information frames' are often insufficient to list everyone involved in a project. The 'Involved people list' is a frame containing the names of those involved, and how they were involved. The body simply contains a terminated string with the involvement directly followed by a terminated string with the involvee followed by a new involvement and so on. There may only be one "IPLS" frame in each tag. <Header for 'Involved people list', ID: "IPLS"> Text encoding $xx People list strings <text strings according to encoding> 4.5. 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. This frame requires a present and valid "TRCK" frame, even if the CD's only got one track. There may only be one "MCDI" frame in each tag. <Header for 'Music CD identifier', ID: "MCDI"> CD TOC <binary data> 4.6. Event timing codes This frame allows synchronisation with key events in a song or sound. The header is: <Header for 'Event timing codes', ID: "ETCO"> 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 Abolute 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 should 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 mainpart 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 mainpart end $12 verse end $13 refrain end $14 theme end $15-$DF reserved for future use $E0-$EF not predefined sync 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 not required. The 'Not predefined sync's ($E0-EF) are for user events. You might want to synchronise your music to something, like setting of an explosion on-stage, turning on your screensaver etc. There may only be one "ETCO" frame in each tag. 4.7. MPEG location lookup table To increase performance and accuracy of jumps within a MPEG [MPEG] audio file, frames with timecodes in different locations in the file might be useful. The ID3v2 frame includes references that the software can use to calculate positions in the file. After the frame header is a descriptor of how much the 'frame counter' should increase 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. <Header for 'Location lookup table', ID: "MLLT"> 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.8. 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 should 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. <Header for 'Synchronised tempo codes', ID: "SYTC"> Time stamp format $xx Tempo data <binary 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 Abolute time means that every stamp contains the time from the beginning of the file. 4.9. Unsychronised 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. <Header for 'Unsynchronised lyrics/text transcription', ID: "USLT"> Text encoding $xx Language $xx xx xx Content descriptor <text string according to encoding> $00 (00) Lyrics/text <full text string according to encoding> 4.10. 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 textstring. If no descriptor is entered, 'Content descriptor' is $00 (00) only. <Header for 'Synchronised lyrics/text', ID: "SYLT"> Text encoding $xx Language $xx xx xx Time stamp format $xx Content type $xx Content descriptor <text string according to encoding> $00 (00) Encoding: $00 ISO-8859-1 [ISO-8859-1] character set is used => $00 is sync identifier. $01 Unicode [UNICODE] character set is used => $00 00 is sync identifier. 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 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 Abolute 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 ($0A) characters are allowed in all "SYLT" frames and should 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.11. Comments This frame is indended 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. <Header for 'Comment', ID: "COMM"> Text encoding $xx Language $xx xx xx Short content descrip. <text string according to encoding> $00 (00) The actual text <full text string according to encoding> 4.12. Relative volume adjustment This is a more subjective function than the previous ones. It allows the user to say how much he wants to increase/decrease the volume on each channel while 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. If the volume peak levels are known then this could be described with the 'Peak volume right' and 'Peak volume left' field. If Peakvolume is not known these fields could be left zeroed or, if no other data follows, be completely omitted. There may only be one "RVAD" frame in each tag. <Header for 'Relative volume adjustment', ID: "RVAD"> Increment/decrement %00xxxxxx Bits used for volume descr. $xx Relative volume change, right $xx xx (xx ...) Relative volume change, left $xx xx (xx ...) Peak volume right $xx xx (xx ...) Peak volume left $xx xx (xx ...) In the increment/decrement field bit 0 is used to indicate the right channel and bit 1 is used to indicate the left channel. 1 is increment and 0 is decrement. The 'bits used for volume description' field is normally $10 (16 bits) for MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value may not be $00. The volume is always represented with whole bytes, padded in the beginning (highest bits) when 'bits used for volume description' is not a multiple of eight. This datablock is then optionally followed by a volume definition for the left and right back channels. If this information is appended to the frame the first two channels will be treated as front channels. In the increment/decrement field bit 2 is used to indicate the right back channel and bit 3 for the left back channel. Relative volume change, right back $xx xx (xx ...) Relative volume change, left back $xx xx (xx ...) Peak volume right back $xx xx (xx ...) Peak volume left back $xx xx (xx ...) If the center channel adjustment is present the following is appended to the existing frame, after the left and right back channels. The center channel is represented by bit 4 in the increase/decrease field. Relative volume change, center $xx xx (xx ...) Peak volume center $xx xx (xx ...) If the bass channel adjustment is present the following is appended to the existing frame, after the center channel. The bass channel is represented by bit 5 in the increase/decrease field. Relative volume change, bass $xx xx (xx ...) Peak volume bass $xx xx (xx ...) 4.13. Equalisation This is another subjective, alignment frame. It allows the user to predefine an equalisation curve within the audio file. There may only be one "EQUA" frame in each tag. <Header of 'Equalisation', ID: "EQUA"> Adjustment bits $xx The 'adjustment bits' field defines the number of bits used for representation of the adjustment. This is normally $10 (16 bits) for MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value may not be $00. This is followed by 2 bytes + ('adjustment bits' rounded up to the nearest byte) for every equalisation band in the following format, giving a frequency range of 0 - 32767Hz: Increment/decrement %x (MSB of the Frequency) Frequency (lower 15 bits) Adjustment $xx (xx ...) The increment/decrement bit is 1 for increment and 0 for decrement. The equalisation bands should be ordered increasingly with reference to frequency. All frequencies don't have to be declared. The equalisation curve in the reading software should be interpolated between the values in this frame. Three equal adjustments for three subsequent frequencies. A frequency should only be described once in the frame. 4.14. Reverb Yet another subjective one. You may here 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. <Header for 'Reverb', ID: "RVRB"> 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.15. 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 textstring. The description has a maximum length of 64 characters, but may be empty. 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. <Header for 'Attached picture', ID: "APIC"> Text encoding $xx MIME type <text string> $00 Picture type $xx Description <text string according to encoding> $00 (00) Picture data <binary 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. lable 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.16. 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. <Header for 'General encapsulated object', ID: "GEOB"> Text encoding $xx MIME type <text string> $00 Filename <text string according to encoding> $00 (00) Content description <text string according to encding> $00 (00) Encapsulated object <binary data> 4.17. 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. <Header for 'Play counter', ID: "PCNT"> Counter $xx xx xx xx (xx ...) 4.18. 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 audiofiles 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 is very simple. It 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. <Header for 'Popularimeter', ID: "POPM"> Email to user <text string> $00 Rating $xx Counter $xx xx xx xx (xx ...) 4.19. Recommended buffer size Sometimes the server from which a 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 audiostream. 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. Every tag that is picked up after the initial/first tag is to be considered as an update of the previous one. E.g. if there is a "TIT2" frame in the first received tag and one in the second tag, then the first should be 'replaced' with the second. The 'Buffer size' should be kept to a minimum. There may only be one "RBUF" frame in each tag. <Header for 'Recommended buffer size', ID: "RBUF"> Buffer size $xx xx xx Embedded info flag %0000000x Offset to next tag $xx xx xx xx 4.20. Audio encryption This frame indicates if the actual audio stream is encrypted, and by whom. Since standardisation of such encrypion 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 audiofile 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 datablock 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'. <Header for 'Audio encryption', ID: "AENC"> Owner identifier <text string> $00 Preview start $xx xx Preview length $xx xx Encryption info <binary data> 4.21. Linked information To keep space waste 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 seperation 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). <Header for 'Linked information', ID: "LINK"> Frame identifier $xx xx xx URL <text string> $00 ID and additional data <text string(s)> Frames that may be linked and need no additional data are "IPLS", "MCID", "ETCO", "MLLT", "SYTC", "RVAD", "EQUA", "RVRB", "RBUF", the text information frames and the URL link frames. The "TXXX", "APIC", "GEOB" and "AENC" frames may be linked with the content descriptor 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.22. 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 of the first frame in the stream. The frame layout is: <Head for 'Position synchronisation', ID: "POSS"> 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.23. 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 only be one "USER" frame in a tag. <Header for 'Terms of use frame', ID: "USER"> Text encoding $xx Language $xx xx xx The actual text <text string according to encoding> 4.24. 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 payed' 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 payed, 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. <Header for 'Ownership frame', ID: "OWNE"> Text encoding $xx Price payed <text string> $00 Date of purch. <text string> Seller <text string according to encoding> 4.25. 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 seperator. In the price string several prices may be concatenated, seperated 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 to attach. <Header for 'Commercial frame', ID: "COMR"> Text encoding $xx Price string <text string> $00 Valid until <text string> Contact URL <text string> $00 Received as $xx Name of seller <text string according to encoding> $00 (00) Description <text string according to encoding> $00 (00) Picture MIME type <string> $00 Seller logo <binary data> 4.26. 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. Values below $80 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 section 3.3.1, flag j for more information. <Header for 'Encryption method registration', ID: "ENCR"> Owner identifier <text string> $00 Method symbol $xx Encryption data <binary data> 4.27. 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. Values below $80 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 section 3.3.1, flag j for more information. <Header for 'Group ID registration', ID: "GRID"> Owner identifier <text string> $00 Group symbol $xx Group dependent data <binary data> 4.28. 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. It is recommended to keep the number of "PRIV" frames as low as possible. <Header for 'Private frame', ID: "PRIV"> Owner identifier <text string> $00 The private data <binary data> 5. The 'unsynchronisation scheme' The only purpose of the 'unsynchronisation scheme' is to make the ID3v2 tag as compatible as possible with existing software. There is no use in 'unsynchronising' tags if the file is only to be processed by new software. Unsynchronisation may only be made with MPEG 2 layer I, II and III and MPEG 2.5 files. Whenever a false synchronisation is found within the tag, one zeroed byte is inserted after the first false synchronisation byte. The format of a correct sync 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 won't 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 first bit in 'ID3 flags' should be set. This bit should only be set if the tag contains a, now corrected, false synchronisation. The bit should only be clear if the tag does not contain any false synchronisations. Do bear in mind, that if a compression scheme is used by the encoder, the unsynchronisation scheme should be applied *afterwards*. When decoding a compressed, 'unsynchronised' file, the 'unsynchronisation scheme' should be parsed first, decompression afterwards. If the last byte in the tag is $FF, and there is a need to eliminate false synchronisations in the tag, at least one byte of padding should be added. 6. Copyright Copyright (C) Martin Nilsson 1998. 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. 7. References [CDDB] Compact Disc Data Base http://www.cddb.com [ID3v2] Martin Nilsson, "ID3v2 informal standard". http://www.id3lib.org/id3/id3v2-00.txt [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 http://www.w3.org/Graphics/JPEG/jfif.txt">http://www.w3.org/Graphics/JPEG/jfif.txt [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996. ftp://ftp.isi.edu/in-notes/rfc2045.txt">ftp://ftp.isi.edu/in-notes/rfc2045.txt [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 http://www.w3.org/TR/REC-png-multi.html [UNICODE] ISO/IEC 10646-1:1993. Universal Multiple-Octet Coded Character Set (UCS), Part 1: Architecture and Basic Multilingual Plane. Technical committee / subcommittee: JTC 1 / SC 2 http://www.unicode.org/ [URL] T. Berners-Lee, L. Masinter & M. McCahill, "Uniform Resource Locators (URL).", RFC 1738, December 1994. ftp://ftp.isi.edu/in-notes/rfc1738.txt [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, "ZLIB Compressed Data Format Specification version 3.3", RFC 1950, May 1996. ftp://ftp.isi.edu/in-notes/rfc1950.txt 8. 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 The following genres are Winamp extensions 80.Folk 81.Folk-Rock 82.National Folk 83.Swing 84.Fast Fusion 85.Bebob 86.Latin 87.Revival 88.Celtic 89.Bluegrass 90.Avantgarde 91.Gothic Rock 92.Progressive Rock 93.Psychedelic Rock 94.Symphonic Rock 95.Slow Rock 96.Big Band 97.Chorus 98.Easy Listening 99.Acoustic 100.Humour 101.Speech 102.Chanson 103.Opera 104.Chamber Music 105.Sonata 106.Symphony 107.Booty Bass 108.Primus 109.Porn Groove 110.Satire 111.Slow Jam 112.Club 113.Tango 114.Samba 115.Folklore 116.Ballad 117.Power Ballad 118.Rhythmic Soul 119.Freestyle 120.Duet 121.Punk Rock 122.Drum Solo 123.Acapella 124.Euro-House 125.Dance Hall 9. Author's Address Written by Martin Nilsson Rydsvgen 246 C. 30 S-584 34 Linkping Sweden Email: nilsson@id3.org Edited by Dirk Mahoney 57 Pechey Street Chermside Q Australia 4032 Email: dirk@id3.org Johan Sundstrm Alsttersgatan 5 A. 34 S-584 35 Linkping Sweden Email: johan@id3.org ����������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2.4.0-frames.txt�������������������������������������������������0000664�0000000�0000000�00000200067�12225024651�0021354�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������$Id$ 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'. <Header for 'Unique file identifier', ID: "UFID"> Owner identifier <text string> $00 Identifier <up to 64 bytes binary data> 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: <Header for 'Text information frame', ID: "T000" - "TZZZ", excluding "TXXX" described in 4.2.6.> Text encoding $xx Information <text string(s) according to encoding> 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. <Header for 'User defined text information frame', ID: "TXXX"> Text encoding $xx Description <text string according to encoding> $00 (00) Value <text string according to encoding> 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: <Header for 'URL link frame', ID: "W000" - "WZZZ", excluding "WXXX" described in 4.3.2.> URL <text string> 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. <Header for 'User defined URL link frame', ID: "WXXX"> Text encoding $xx Description <text string according to encoding> $00 (00) URL <text string> 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. <Header for 'Music CD identifier', ID: "MCDI"> CD TOC <binary data> 4.5. Event timing codes This frame allows synchronisation with key events in the audio. The header is: <Header for 'Event timing codes', ID: "ETCO"> 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. <Header for 'Location lookup table', ID: "MLLT"> 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. <Header for 'Synchronised tempo codes', ID: "SYTC"> Time stamp format $xx Tempo data <binary 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. <Header for 'Unsynchronised lyrics/text transcription', ID: "USLT"> Text encoding $xx Language $xx xx xx Content descriptor <text string according to encoding> $00 (00) Lyrics/text <full text string according to encoding> 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. <Header for 'Synchronised lyrics/text', ID: "SYLT"> Text encoding $xx Language $xx xx xx Time stamp format $xx Content type $xx Content descriptor <text string according to encoding> $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. <Header for 'Comment', ID: "COMM"> Text encoding $xx Language $xx xx xx Short content descrip. <text string according to encoding> $00 (00) The actual text <full text string according to encoding> 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. <Header for 'Relative volume adjustment (2)', ID: "RVA2"> Identification <text string> $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. <Header of 'Equalisation (2)', ID: "EQU2"> Interpolation method $xx Identification <text string> $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. <Header for 'Reverb', ID: "RVRB"> 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. <Header for 'Attached picture', ID: "APIC"> Text encoding $xx MIME type <text string> $00 Picture type $xx Description <text string according to encoding> $00 (00) Picture data <binary 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. <Header for 'General encapsulated object', ID: "GEOB"> Text encoding $xx MIME type <text string> $00 Filename <text string according to encoding> $00 (00) Content description <text string according to encoding> $00 (00) Encapsulated object <binary data> 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. <Header for 'Play counter', ID: "PCNT"> 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. <Header for 'Popularimeter', ID: "POPM"> Email to user <text string> $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. <Header for 'Recommended buffer size', ID: "RBUF"> 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'. <Header for 'Audio encryption', ID: "AENC"> Owner identifier <text string> $00 Preview start $xx xx Preview length $xx xx Encryption info <binary data> 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). <Header for 'Linked information', ID: "LINK"> Frame identifier $xx xx xx xx URL <text string> $00 ID and additional data <text string(s)> 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: <Head for 'Position synchronisation', ID: "POSS"> 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'. <Header for 'Terms of use frame', ID: "USER"> Text encoding $xx Language $xx xx xx The actual text <text string according to encoding> 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. <Header for 'Ownership frame', ID: "OWNE"> Text encoding $xx Price paid <text string> $00 Date of purch. <text string> Seller <text string according to encoding> 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. <Header for 'Commercial frame', ID: "COMR"> Text encoding $xx Price string <text string> $00 Valid until <text string> Contact URL <text string> $00 Received as $xx Name of seller <text string according to encoding> $00 (00) Description <text string according to encoding> $00 (00) Picture MIME type <string> $00 Seller logo <binary data> 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. <Header for 'Encryption method registration', ID: "ENCR"> Owner identifier <text string> $00 Method symbol $xx Encryption data <binary 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. <Header for 'Group ID registration', ID: "GRID"> Owner identifier <text string> $00 Group symbol $xx Group dependent data <binary 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. <Header for 'Private frame', ID: "PRIV"> Owner identifier <text string> $00 The private data <binary 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. <Header for 'Signature frame', ID: "SIGN"> Group symbol $xx Signature <binary data> 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. <Header for 'Seek frame', ID: "SEEK"> 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. <Header for 'Seek Point Index', ID: "ASPI"> 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 <url:http://www.cddb.com> [ID3v2.3.0] Martin Nilsson, "ID3v2 informal standard". <url:http://www.id3.org/id3v2.3.0.txt> [ID3v2-strct] Martin Nilsson, "ID3 tag version 2.4.0 - Main Structure" <url:http//www.id3.org/id3v2.4.0-structure.txt> [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 <url:http://www.w3.org/Graphics/JPEG/jfif.txt> [KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate Requirement Levels', RFC 2119, March 1997. <url:ftp://ftp.isi.edu/in-notes/rfc2119.txt> [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996. <url:ftp://ftp.isi.edu/in-notes/rfc2045.txt> [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:http://www.w3.org/TR/REC-png-multi.html> [URL] T. Berners-Lee, L. Masinter & M. McCahill, "Uniform Resource Locators (URL).", RFC 1738, December 1994. <url:ftp://ftp.isi.edu/in-notes/rfc1738.txt> [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, "ZLIB Compressed Data Format Specification version 3.3", RFC 1950, May 1996. <url:ftp://ftp.isi.edu/in-notes/rfc1950.txt> 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 Rydsvgen 246 C. 30 SE-584 34 Linkping Sweden Email: nilsson@id3.org �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2.4.0-structure.txt����������������������������������������������0000664�0000000�0000000�00000067445�12225024651�0022152�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 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 <text string>, or <full text string> 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 <text string according to encoding>, or <full text string according to encoding> 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'. <url:http://www.id3.org/id3v2.3.0.txt> [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' <url:http://www.w3.org/Graphics/JPEG/jfif.txt> [KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate Requirement Levels', RFC 2119, March 1997. <url:ftp://ftp.isi.edu/in-notes/rfc2119.txt> [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:http://www.w3.org/TR/REC-png-multi.html> [UNICODE] The Unicode Consortium, 'The Unicode Standard Version 3.0', ISBN 0-201-61633-5. <url:http://www.unicode.org/unicode/standard/versions/Unicode3.0.htm> [URL] T. Berners-Lee, L. Masinter & M. McCahill, 'Uniform Resource Locators (URL)', RFC 1738, December 1994. <url:ftp://ftp.isi.edu/in-notes/rfc1738.txt> [UTF-8] F. Yergeau, 'UTF-8, a transformation format of ISO 10646', RFC 2279, January 1998. <url:ftp://ftp.isi.edu/in-notes/rfc2279.txt> [UTF-16] F. Yergeau, 'UTF-16, an encoding of ISO 10646', RFC 2781, February 2000. <url:ftp://ftp.isi.edu/in-notes/rfc2781.txt> [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, 'ZLIB Compressed Data Format Specification version 3.3', RFC 1950, May 1996. <url:ftp://ftp.isi.edu/in-notes/rfc1950.txt> 9. Author's Address Written by Martin Nilsson Rydsvgen 246 C. 30 SE-584 34 Linkping Sweden Email: nilsson@id3.org ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2extendedheader.cpp����������������������������������������������0000664�0000000�0000000�00000005234�12225024651�0022435�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "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") } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2extendedheader.h������������������������������������������������0000664�0000000�0000000�00000007056�12225024651�0022106�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V2EXTENDEDHEADER_H #define TAGLIB_ID3V2EXTENDEDHEADER_H #include "taglib_export.h" #include "tbytevector.h" #include "taglib.h" 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, <a href="id3v2-structure.html#3.2">3.2</a>) */ class TAGLIB_EXPORT 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 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2footer.cpp������������������������������������������������������0000664�0000000�0000000�00000004240�12225024651�0020756�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "id3v2footer.h" #include "id3v2header.h" using namespace TagLib; using namespace ID3v2; class Footer::FooterPrivate { public: static const uint size = 10; }; Footer::Footer() { } Footer::~Footer() { } TagLib::uint 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; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2footer.h��������������������������������������������������������0000664�0000000�0000000�00000005717�12225024651�0020435�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V2FOOTER_H #define TAGLIB_ID3V2FOOTER_H #include "taglib_export.h" #include "tbytevector.h" 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 TAGLIB_EXPORT 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 uint 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 �������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2frame.cpp�������������������������������������������������������0000664�0000000�0000000�00000054272�12225024651�0020564�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #if HAVE_ZLIB #include <zlib.h> #endif #include <bitset> #include <tdebug.h> #include <tstringlist.h> #include "id3v2tag.h" #include "id3v2frame.h" #include "id3v2synchdata.h" #include "tpropertymap.h" #include "frames/textidentificationframe.h" #include "frames/urllinkframe.h" #include "frames/unsynchronizedlyricsframe.h" #include "frames/commentsframe.h" #include "frames/uniquefileidentifierframe.h" #include "frames/unknownframe.h" using namespace TagLib; using namespace ID3v2; class Frame::FramePrivate { public: FramePrivate() : header(0) {} ~FramePrivate() { delete header; } Frame::Header *header; }; namespace { bool isValidFrameID(const ByteVector &frameID) { if(frameID.size() != 4) return false; for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) { return false; } } return true; } } //////////////////////////////////////////////////////////////////////////////// // 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 || t == String::UTF16LE) d.append(char(0)); return d; } const String Frame::instrumentPrefix("PERFORMER:"); const String Frame::commentPrefix("COMMENT:"); const String Frame::lyricsPrefix("LYRICS:"); const String Frame::urlPrefix("URL:"); //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// Frame *Frame::createTextualFrame(const String &key, const StringList &values) //static { // check if the key is contained in the key<=>frameID mapping ByteVector frameID = keyToFrameID(key); if(!frameID.isNull()) { if(frameID[0] == 'T'){ // text frame TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8); frame->setText(values); return frame; } else if((frameID[0] == 'W') && (values.size() == 1)){ // URL frame (not WXXX); support only one value UrlLinkFrame* frame = new UrlLinkFrame(frameID); frame->setUrl(values.front()); return frame; } } if(key == "MUSICBRAINZ_TRACKID" && values.size() == 1) { UniqueFileIdentifierFrame *frame = new UniqueFileIdentifierFrame("http://musicbrainz.org", values.front().data(String::UTF8)); return frame; } // now we check if it's one of the "special" cases: // -LYRICS: depending on the number of values, use USLT or TXXX (with description=LYRICS) if((key == "LYRICS" || key.startsWith(lyricsPrefix)) && values.size() == 1){ UnsynchronizedLyricsFrame *frame = new UnsynchronizedLyricsFrame(String::UTF8); frame->setDescription(key == "LYRICS" ? key : key.substr(lyricsPrefix.size())); frame->setText(values.front()); return frame; } // -URL: depending on the number of values, use WXXX or TXXX (with description=URL) if((key == "URL" || key.startsWith(urlPrefix)) && values.size() == 1){ UserUrlLinkFrame *frame = new UserUrlLinkFrame(String::UTF8); frame->setDescription(key == "URL" ? key : key.substr(urlPrefix.size())); frame->setUrl(values.front()); return frame; } // -COMMENT: depending on the number of values, use COMM or TXXX (with description=COMMENT) if((key == "COMMENT" || key.startsWith(commentPrefix)) && values.size() == 1){ CommentsFrame *frame = new CommentsFrame(String::UTF8); if (key != "COMMENT"){ frame->setDescription(key.substr(commentPrefix.size())); } frame->setText(values.front()); return frame; } // if non of the above cases apply, we use a TXXX frame with the key as description return new UserTextIdentificationFrame(keyToTXXX(key), values, String::UTF8); } 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 = SynchData::toUInt(frameData.mid(headerSize, 4)); frameDataOffset += 4; } #if HAVE_ZLIB if(d->header->compression() && !d->header->encryption()) { 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); } String Frame::readStringField(const ByteVector &data, String::Type encoding, int *position) { int start = 0; if(!position) position = &start; ByteVector delimiter = textDelimiter(encoding); int end = data.find(delimiter, *position, delimiter.size()); if(end < *position) return String::null; String str; if(encoding == String::Latin1) str = Tag::latin1StringHandler()->parse(data.mid(*position, end - *position)); else str = String(data.mid(*position, end - *position), encoding); *position = end + delimiter.size(); return str; } String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding) // static { return checkEncoding(fields, encoding, 4); } String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding, uint version) // static { if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4) return String::UTF16; if(encoding != String::Latin1) return encoding; for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) { if(!(*it).isLatin1()) { if(version == 4) { debug("Frame::checkEncoding() -- Rendering using UTF8."); return String::UTF8; } else { debug("Frame::checkEncoding() -- Rendering using UTF16."); return String::UTF16; } } } return String::Latin1; } String::Type Frame::checkTextEncoding(const StringList &fields, String::Type encoding) const { return checkEncoding(fields, encoding, header()->version()); } static const TagLib::uint frameTranslationSize = 51; static const char *frameTranslation[][2] = { // Text information frames { "TALB", "ALBUM"}, { "TBPM", "BPM" }, { "TCOM", "COMPOSER" }, { "TCON", "GENRE" }, { "TCOP", "COPYRIGHT" }, { "TDEN", "ENCODINGTIME" }, { "TDLY", "PLAYLISTDELAY" }, { "TDOR", "ORIGINALDATE" }, { "TDRC", "DATE" }, // { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 // { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 // { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 // { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 { "TDRL", "RELEASEDATE" }, { "TDTG", "TAGGINGDATE" }, { "TENC", "ENCODEDBY" }, { "TEXT", "LYRICIST" }, { "TFLT", "FILETYPE" }, //{ "TIPL", "INVOLVEDPEOPLE" }, handled separately { "TIT1", "CONTENTGROUP" }, { "TIT2", "TITLE"}, { "TIT3", "SUBTITLE" }, { "TKEY", "INITIALKEY" }, { "TLAN", "LANGUAGE" }, { "TLEN", "LENGTH" }, //{ "TMCL", "MUSICIANCREDITS" }, handled separately { "TMED", "MEDIA" }, { "TMOO", "MOOD" }, { "TOAL", "ORIGINALALBUM" }, { "TOFN", "ORIGINALFILENAME" }, { "TOLY", "ORIGINALLYRICIST" }, { "TOPE", "ORIGINALARTIST" }, { "TOWN", "OWNER" }, { "TPE1", "ARTIST"}, { "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST' { "TPE3", "CONDUCTOR" }, { "TPE4", "REMIXER" }, // could also be ARRANGER { "TPOS", "DISCNUMBER" }, { "TPRO", "PRODUCEDNOTICE" }, { "TPUB", "LABEL" }, { "TRCK", "TRACKNUMBER" }, { "TRSN", "RADIOSTATION" }, { "TRSO", "RADIOSTATIONOWNER" }, { "TSOA", "ALBUMSORT" }, { "TSOP", "ARTISTSORT" }, { "TSOT", "TITLESORT" }, { "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes { "TSRC", "ISRC" }, { "TSSE", "ENCODING" }, // URL frames { "WCOP", "COPYRIGHTURL" }, { "WOAF", "FILEWEBPAGE" }, { "WOAR", "ARTISTWEBPAGE" }, { "WOAS", "AUDIOSOURCEWEBPAGE" }, { "WORS", "RADIOSTATIONWEBPAGE" }, { "WPAY", "PAYMENTWEBPAGE" }, { "WPUB", "PUBLISHERWEBPAGE" }, //{ "WXXX", "URL"}, handled specially // Other frames { "COMM", "COMMENT" }, //{ "USLT", "LYRICS" }, handled specially }; static const TagLib::uint txxxFrameTranslationSize = 8; static const char *txxxFrameTranslation[][2] = { { "MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" }, { "MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" }, { "MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" }, { "MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" }, { "MusicBrainz Work Id", "MUSICBRAINZ_WORKID" }, { "Acoustid Id", "ACOUSTID_ID" }, { "Acoustid Fingerprint", "ACOUSTID_FINGERPRINT" }, { "MusicIP PUID", "MUSICIP_PUID" }, }; Map<ByteVector, String> &idMap() { static Map<ByteVector, String> m; if(m.isEmpty()) for(size_t i = 0; i < frameTranslationSize; ++i) m[frameTranslation[i][0]] = frameTranslation[i][1]; return m; } Map<String, String> &txxxMap() { static Map<String, String> m; if(m.isEmpty()) { for(size_t i = 0; i < txxxFrameTranslationSize; ++i) { String key = String(txxxFrameTranslation[i][0]).upper(); m[key] = txxxFrameTranslation[i][1]; } } return m; } // list of deprecated frames and their successors static const TagLib::uint deprecatedFramesSize = 4; static const char *deprecatedFrames[][2] = { {"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3) {"TDAT", "TDRC"}, // 2.3 -> 2.4 {"TYER", "TDRC"}, // 2.3 -> 2.4 {"TIME", "TDRC"}, // 2.3 -> 2.4 }; Map<ByteVector,ByteVector> &deprecationMap() { static Map<ByteVector,ByteVector> depMap; if(depMap.isEmpty()) for(TagLib::uint i = 0; i < deprecatedFramesSize; ++i) depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1]; return depMap; } String Frame::frameIDToKey(const ByteVector &id) { Map<ByteVector, String> &m = idMap(); if(m.contains(id)) return m[id]; if(deprecationMap().contains(id)) return m[deprecationMap()[id]]; return String::null; } ByteVector Frame::keyToFrameID(const String &s) { static Map<String, ByteVector> m; if(m.isEmpty()) for(size_t i = 0; i < frameTranslationSize; ++i) m[frameTranslation[i][1]] = frameTranslation[i][0]; if(m.contains(s.upper())) return m[s]; return ByteVector::null; } String Frame::txxxToKey(const String &description) { Map<String, String> &m = txxxMap(); String d = description.upper(); if(m.contains(d)) return m[d]; return d; } String Frame::keyToTXXX(const String &s) { static Map<String, String> m; if(m.isEmpty()) for(size_t i = 0; i < txxxFrameTranslationSize; ++i) m[txxxFrameTranslation[i][1]] = txxxFrameTranslation[i][0]; if(m.contains(s.upper())) return m[s]; return s; } PropertyMap Frame::asProperties() const { if(dynamic_cast< const UnknownFrame *>(this)) { PropertyMap m; m.unsupportedData().append("UNKNOWN/" + frameID()); return m; } const ByteVector &id = frameID(); // workaround until this function is virtual if(id == "TXXX") return dynamic_cast< const UserTextIdentificationFrame* >(this)->asProperties(); else if(id[0] == 'T') return dynamic_cast< const TextIdentificationFrame* >(this)->asProperties(); else if(id == "WXXX") return dynamic_cast< const UserUrlLinkFrame* >(this)->asProperties(); else if(id[0] == 'W') return dynamic_cast< const UrlLinkFrame* >(this)->asProperties(); else if(id == "COMM") return dynamic_cast< const CommentsFrame* >(this)->asProperties(); else if(id == "USLT") return dynamic_cast< const UnsynchronizedLyricsFrame* >(this)->asProperties(); else if(id == "UFID") return dynamic_cast< const UniqueFileIdentifierFrame* >(this)->asProperties(); PropertyMap m; m.unsupportedData().append(id); return m; } void Frame::splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, PropertyMap &tiplProperties, PropertyMap &tmclProperties) { singleFrameProperties.clear(); tiplProperties.clear(); tmclProperties.clear(); for(PropertyMap::ConstIterator it = original.begin(); it != original.end(); ++it) { if(TextIdentificationFrame::involvedPeopleMap().contains(it->first)) tiplProperties.insert(it->first, it->second); else if(it->first.startsWith(TextIdentificationFrame::instrumentPrefix)) tmclProperties.insert(it->first, it->second); else singleFrameProperties.insert(it->first, it->second); } } //////////////////////////////////////////////////////////////////////////////// // 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), unsynchronisation(false), dataLengthIndicator(false) {} ByteVector frameID; uint frameSize; uint version; // flags bool tagAlterPreservation; bool fileAlterPreservation; bool readOnly; bool groupingIdentity; bool compression; bool encryption; bool unsynchronisation; 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.toUInt(3, 3, true); 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.toUInt(4U); { // 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)); #ifndef NO_ITUNES_HACKS // iTunes writes v2.4 tags with v2.3-like frame sizes if(d->frameSize > 127) { if(!isValidFrameID(data.mid(d->frameSize + 10, 4))) { unsigned int uintSize = data.toUInt(4U); if(isValidFrameID(data.mid(uintSize + 10, 4))) { d->frameSize = uintSize; } } } #endif { // 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->unsynchronisation = 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; } void Frame::Header::setVersion(TagLib::uint version) { d->version = version; } bool Frame::Header::tagAlterPreservation() const { return d->tagAlterPreservation; } void Frame::Header::setTagAlterPreservation(bool preserve) { d->tagAlterPreservation = preserve; } 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 unsynchronisation(); } bool Frame::Header::unsynchronisation() const { return d->unsynchronisation; } 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 + (d->version == 3 ? ByteVector::fromUInt(d->frameSize) : SynchData::fromUInt(d->frameSize)) + flags; return v; } bool Frame::Header::frameAlterPreservation() const { return fileAlterPreservation(); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2frame.h���������������������������������������������������������0000664�0000000�0000000�00000044516�12225024651�0020231�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V2FRAME_H #define TAGLIB_ID3V2FRAME_H #include "tstring.h" #include "tbytevector.h" #include "taglib_export.h" namespace TagLib { class StringList; class PropertyMap; namespace ID3v2 { class Tag; 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, <a href="id3v2-structure.html#4">4</a>) * (<a href="id3v2-frames.html">Frames</a>). 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 TAGLIB_EXPORT Frame { friend class Tag; friend class FrameFactory; public: /*! * Creates a textual frame which corresponds to a single key in the PropertyMap * interface. These are all (User)TextIdentificationFrames except TIPL and TMCL, * all (User)URLLinkFrames, CommentsFrames, and UnsynchronizedLyricsFrame. */ static Frame *createTextualFrame(const String &key, const StringList &values); /*! * Destroys this Frame instance. */ virtual ~Frame(); /*! * Returns the Frame ID (Structure, <a href="id3v2-structure.html#4">4</a>) * (Frames, <a href="id3v2-frames.html#4">4</a>) */ 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); /*! * The string with which an instrument name is prefixed to build a key in a PropertyMap; * used to translate PropertyMaps to TMCL frames. In the current implementation, this * is "PERFORMER:". */ static const String instrumentPrefix; /*! * The PropertyMap key prefix which triggers the use of a COMM frame instead of a TXXX * frame for a non-standard key. In the current implementation, this is "COMMENT:". */ static const String commentPrefix; /*! * The PropertyMap key prefix which triggers the use of a USLT frame instead of a TXXX * frame for a non-standard key. In the current implementation, this is "LYRICS:". */ static const String lyricsPrefix; /*! * The PropertyMap key prefix which triggers the use of a WXXX frame instead of a TXX * frame for a non-standard key. In the current implementation, this is "URL:". */ static const String urlPrefix; 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; /*! * Reads a String of type \a encodiong from the ByteVector \a data. If \a * position is passed in it is used both as the starting point and is * updated to replect the position just after the string that has been read. * This is useful for reading strings sequentially. */ String readStringField(const ByteVector &data, String::Type encoding, int *positon = 0); /*! * Checks a the list of string values to see if they can be used with the * specified encoding and returns the recommended encoding. */ // BIC: remove and make non-static static String::Type checkEncoding(const StringList &fields, String::Type encoding); /*! * Checks a the list of string values to see if they can be used with the * specified encoding and returns the recommended encoding. This method * also checks the ID3v2 version and makes sure the encoding can be used * in the specified version. */ // BIC: remove and make non-static static String::Type checkEncoding(const StringList &fields, String::Type encoding, uint version); /*! * Checks a the list of string values to see if they can be used with the * specified encoding and returns the recommended encoding. This method * also checks the ID3v2 version and makes sure the encoding can be used * in the version specified by the frame's header. */ String::Type checkTextEncoding(const StringList &fields, String::Type encoding) const; /*! * Parses the contents of this frame as PropertyMap. If that fails, the returend * PropertyMap will be empty, and its unsupportedData() will contain this frame's * ID. * BIC: Will be a virtual function in future releases. */ PropertyMap asProperties() const; /*! * Returns an appropriate ID3 frame ID for the given free-form tag key. This method * will return ByteVector::null if no specialized translation is found. */ static ByteVector keyToFrameID(const String &); /*! * Returns a free-form tag name for the given ID3 frame ID. Note that this does not work * for general frame IDs such as TXXX or WXXX; in such a case String::null is returned. */ static String frameIDToKey(const ByteVector &); /*! * Returns an appropriate TXXX frame description for the given free-form tag key. */ static String keyToTXXX(const String &); /*! * Returns a free-form tag name for the given ID3 frame description. */ static String txxxToKey(const String &); /*! * This helper function splits the PropertyMap \a original into three ProperytMaps * \a singleFrameProperties, \a tiplProperties, and \a tmclProperties, such that: * - \a singleFrameProperties contains only of keys which can be represented with * exactly one ID3 frame per key. In the current implementation * this is everything except for the fixed "involved people" keys and keys of the * form "TextIdentificationFrame::instrumentPrefix" + "instrument", which are * mapped to a TMCL frame. * - \a tiplProperties will consist of those keys that are present in * TextIdentificationFrame::involvedPeopleMap() * - \a tmclProperties contains the "musician credits" keys which should be mapped * to a TMCL frame */ static void splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, PropertyMap &tiplProperties, PropertyMap &tmclProperties); private: Frame(const Frame &); Frame &operator=(const Frame &); class FramePrivate; friend class FramePrivate; FramePrivate *d; }; //! ID3v2 frame header implementation /*! * The ID3v2 Frame Header (Structure, <a href="id3v2-structure.html#4">4</a>) * * 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 TAGLIB_EXPORT 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, <a href="id3v2-structure.html#4">4</a>) * (Frames, <a href="id3v2-frames.html#4">4</a>) */ 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 explicitly 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 or set via setVersion(). */ uint version() const; /*! * Sets the ID3v2 version of the header, changing has impact on the * correct parsing/rendering of frame data. */ void setVersion(uint version); /*! * 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. * * The semantics are a little backwards from what would seem natural * (setting the preservation flag to throw away the frame), but this * follows the ID3v2 standard. * * \see setTagAlterPreservation() */ bool tagAlterPreservation() const; /*! * Sets the flag for preservation of this frame if the tag is set. If * this is set to true the frame will not be written when the tag is * saved. * * The semantics are a little backwards from what would seem natural * (setting the preservation flag to throw away the frame), but this * follows the ID3v2 standard. * * \see tagAlterPreservation() */ void setTagAlterPreservation(bool discard); /*! * 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; #ifndef DO_NOT_DOCUMENT bool unsycronisation() const; #endif /*! * Returns true if unsynchronisation is enabled for this frame. */ bool unsynchronisation() const; /*! * Returns true if the flag for a data length 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 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2framefactory.cpp������������������������������������������������0000664�0000000�0000000�00000032646�12225024651�0022155�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <tdebug.h> #include "id3v2framefactory.h" #include "id3v2synchdata.h" #include "id3v1genres.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" #include "frames/generalencapsulatedobjectframe.h" #include "frames/urllinkframe.h" #include "frames/unsynchronizedlyricsframe.h" #include "frames/popularimeterframe.h" #include "frames/privateframe.h" #include "frames/ownershipframe.h" using namespace TagLib; using namespace ID3v2; class FrameFactory::FrameFactoryPrivate { public: FrameFactoryPrivate() : defaultEncoding(String::Latin1), useDefaultEncoding(false) {} String::Type defaultEncoding; bool useDefaultEncoding; template <class T> void setTextEncoding(T *frame) { if(useDefaultEncoding) frame->setTextEncoding(defaultEncoding); } }; FrameFactory FrameFactory::factory; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// FrameFactory *FrameFactory::instance() { 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 { Header tagHeader; tagHeader.setMajorVersion(version); return createFrame(data, &tagHeader); } Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const { ByteVector data = origData; uint version = tagHeader->majorVersion(); 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() <= uint(header->dataLengthIndicator() ? 4 : 0) || header->frameSize() > data.size()) { delete header; return 0; } #ifndef NO_ITUNES_HACKS if(version == 3 && frameID.size() == 4 && frameID[3] == '\0') { // iTunes v2.3 tags store v2.2 frames - convert now frameID = frameID.mid(0, 3); header->setFrameID(frameID); header->setVersion(2); updateFrame(header); header->setVersion(3); } #endif for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) { delete header; return 0; } } if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) { // Data lengths are not part of the encoded data, but since they are synch-safe // integers they will be never actually encoded. ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize()); frameData = SynchData::decode(frameData); data = data.mid(0, Frame::Header::size(version)) + frameData; } // TagLib doesn't mess with encrypted frames, so just treat them // as unknown frames. #if !defined(HAVE_ZLIB) || 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)) { header->setTagAlterPreservation(true); return new UnknownFrame(data, header); } // updateFrame() might have updated the frame ID. frameID = header->frameID(); // 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); d->setTextEncoding(f); if(frameID == "TCON") updateGenre(f); return f; } // Comments (frames 4.10) if(frameID == "COMM") { CommentsFrame *f = new CommentsFrame(data, header); d->setTextEncoding(f); return f; } // Attached Picture (frames 4.14) if(frameID == "APIC") { AttachedPictureFrame *f = new AttachedPictureFrame(data, header); d->setTextEncoding(f); return f; } // ID3v2.2 Attached Picture if(frameID == "PIC") { AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header); d->setTextEncoding(f); 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); // General Encapsulated Object (frames 4.15) if(frameID == "GEOB") { GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header); d->setTextEncoding(f); return f; } // URL link (frames 4.3) if(frameID.startsWith("W")) { if(frameID != "WXXX") { return new UrlLinkFrame(data, header); } else { UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header); d->setTextEncoding(f); return f; } } // Unsynchronized lyric/text transcription (frames 4.8) if(frameID == "USLT") { UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header); if(d->useDefaultEncoding) f->setTextEncoding(d->defaultEncoding); return f; } // Popularimeter (frames 4.17) if(frameID == "POPM") return new PopularimeterFrame(data, header); // Private (frames 4.27) if(frameID == "PRIV") return new PrivateFrame(data, header); // Ownership (frames 4.22) if(frameID == "OWNE") { OwnershipFrame *f = new OwnershipFrame(data, header); d->setTextEncoding(f); return f; } 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" || frameID == "TDA") { 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("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("TCP", "TCMP", header); convertFrame("TCR", "TCOP", 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("TS2", "TSO2", header); convertFrame("TSA", "TSOA", header); convertFrame("TSC", "TSOC", header); convertFrame("TSP", "TSOP", header); convertFrame("TSS", "TSSE", header); convertFrame("TST", "TSOT", 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" || frameID == "TDAT") { debug("ID3v2.4 no longer supports the frame type " + String(frameID) + ". It will be discarded from the tag."); return false; } convertFrame("TORY", "TDOR", header); convertFrame("TYER", "TDRC", header); convertFrame("IPLS", "TIPL", 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); } void FrameFactory::updateGenre(TextIdentificationFrame *frame) const { StringList fields = frame->fieldList(); StringList newfields; for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) { String s = *it; int end = s.find(")"); if(s.startsWith("(") && end > 0) { // "(12)Genre" String text = s.substr(end + 1); bool ok; int number = s.substr(1, end - 1).toInt(&ok); if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text)) newfields.append(s.substr(1, end - 1)); if(!text.isEmpty()) newfields.append(text); } else { // "Genre" or "12" newfields.append(s); } } if(newfields.isEmpty()) fields.append(String::null); frame->setText(newfields); } ������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2framefactory.h��������������������������������������������������0000664�0000000�0000000�00000015247�12225024651�0021620�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V2FRAMEFACTORY_H #define TAGLIB_ID3V2FRAMEFACTORY_H #include "taglib_export.h" #include "tbytevector.h" #include "id3v2frame.h" #include "id3v2header.h" namespace TagLib { namespace ID3v2 { class TextIdentificationFrame; //! A factory for creating ID3v2 frames during parsing /*! * 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 <i>abstract factory</i> and <i>singleton</i> patterns * of which more information is available on the web and in software design * textbooks (Notably <i>Design Patters</i>). * * \note You do not need to use this factory to create new frames to add to * an ID3v2::Tag. You can instantiate frame subclasses directly (with new) * and add them to a tag using ID3v2::Tag::addFrame() * * \see ID3v2::Tag::addFrame() */ class TAGLIB_EXPORT 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 a ID3v2::Header * instance 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. * * \deprecated Please use the method below that accepts a ID3v2::Header * instance in new code. */ Frame *createFrame(const ByteVector &data, uint version = 4) const; /*! * Create a frame based on \a data. \a tagHeader should be a valid * ID3v2::Header instance. */ // BIC: make virtual Frame *createFrame(const ByteVector &data, Header *tagHeader) 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. * * Valid string types for ID3v2 tags are Latin1, UTF8, UTF16 and UTF16BE. * * \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. */ 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; void updateGenre(TextIdentificationFrame *frame) const; static FrameFactory factory; class FrameFactoryPrivate; FrameFactoryPrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2header.cpp������������������������������������������������������0000664�0000000�0000000�00000015051�12225024651�0020712�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <iostream> #include <bitset> #include <tstring.h> #include <tdebug.h> #include "id3v2header.h" #include "id3v2footer.h" #include "id3v2synchdata.h" using namespace TagLib; using namespace ID3v2; class Header::HeaderPrivate { public: HeaderPrivate() : majorVersion(4), 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; } void Header::setMajorVersion(TagLib::uint version) { d->majorVersion = version; } 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(majorVersion())); v.append(char(0)); // Currently we don't actually support writing extended headers, footers or // unsynchronized tags, make sure that the flags are set accordingly. d->extendedHeader = false; d->footerPresent = false; d->unsynchronisation = false; // 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") } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2header.h��������������������������������������������������������0000664�0000000�0000000�00000013251�12225024651�0020357�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V2HEADER_H #define TAGLIB_ID3V2HEADER_H #include "tbytevector.h" #include "taglib_export.h" 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, <a href="id3v2-structure.html#3.1">3.1</a>) */ class TAGLIB_EXPORT 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; /*! * Set the the major version number to \a version. (Note: This is * the 4, not the 2 in ID3v2.4.0. The 2 is implied.) * \see majorVersion() * * \note This is used by the internal parser; this will not change the * version which is written and in general should not be called by API * users. */ void setMajorVersion(uint version); /*! * 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 header. 10 bytes, starting from * the beginning of \a data are 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 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2synchdata.cpp���������������������������������������������������0000664�0000000�0000000�00000005503�12225024651�0021441�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <iostream> #include "id3v2synchdata.h" using namespace TagLib; using namespace ID3v2; TagLib::uint SynchData::toUInt(const ByteVector &data) { uint sum = 0; bool notSynchSafe = false; int last = data.size() > 4 ? 3 : data.size() - 1; for(int i = 0; i <= last; i++) { if(data[i] & 0x80) { notSynchSafe = true; break; } sum |= (data[i] & 0x7f) << ((last - i) * 7); } if(notSynchSafe) { // Invalid data; assume this was created by some buggy software that just // put normal integers here rather than syncsafe ones, and try it that // way. if(data.size() >= 4) { sum = data.toUInt(0, true); } else { ByteVector tmp(data); tmp.resize(4); sum = tmp.toUInt(0, true); } } 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; } ByteVector SynchData::decode(const ByteVector &data) { ByteVector result = data; ByteVector pattern(2, char(0)); pattern[0] = '\xFF'; pattern[1] = '\x00'; return result.replace(pattern, '\xFF'); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2synchdata.h�����������������������������������������������������0000664�0000000�0000000�00000005724�12225024651�0021113�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V2SYNCHDATA_H #define TAGLIB_ID3V2SYNCHDATA_H #include "tbytevector.h" #include "taglib.h" 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, * <a href="id3v2-structure.html#6.2">6.2</a>). The default \a length of * 4 is used if another value is not specified. */ TAGLIB_EXPORT uint toUInt(const ByteVector &data); /*! * Returns a 4 byte (32 bit) synchsafe integer based on \a value. */ TAGLIB_EXPORT ByteVector fromUInt(uint value); /*! * Convert the data from unsynchronized data to its original format. */ TAGLIB_EXPORT ByteVector decode(const ByteVector &input); } } } #endif ��������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2tag.cpp���������������������������������������������������������0000664�0000000�0000000�00000051123�12225024651�0020235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <tfile.h> #include "id3v2tag.h" #include "id3v2header.h" #include "id3v2extendedheader.h" #include "id3v2footer.h" #include "id3v2synchdata.h" #include "tbytevector.h" #include "id3v1genres.h" #include "tpropertymap.h" #include <tdebug.h> #include "frames/textidentificationframe.h" #include "frames/commentsframe.h" #include "frames/urllinkframe.h" #include "frames/uniquefileidentifierframe.h" #include "frames/unsynchronizedlyricsframe.h" #include "frames/unknownframe.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; static const Latin1StringHandler *stringHandler; }; static const Latin1StringHandler defaultStringHandler; const ID3v2::Latin1StringHandler *ID3v2::Tag::TagPrivate::stringHandler = &defaultStringHandler; //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// Latin1StringHandler::Latin1StringHandler() { } Latin1StringHandler::~Latin1StringHandler() { } String Latin1StringHandler::parse(const ByteVector &data) const { return String(data, String::Latin1); } //////////////////////////////////////////////////////////////////////////////// // 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 { const FrameList &comments = d->frameListMap["COMM"]; if(comments.isEmpty()) return String::null; for(FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it); if(frame && frame->description().isEmpty()) return (*it)->toString(); } return comments.front()->toString(); } 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<TextIdentificationFrame *>(d->frameListMap["TCON"].front())) { return String::null; } // 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. TextIdentificationFrame *f = static_cast<TextIdentificationFrame *>( d->frameListMap["TCON"].front()); StringList fields = f->fieldList(); StringList genres; for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) { if((*it).isEmpty()) continue; bool ok; int number = (*it).toInt(&ok); if(ok && number >= 0 && number <= 255) { *it = ID3v1::genre(number); } if(std::find(genres.begin(), genres.end(), *it) == genres.end()) genres.append(*it); } return genres.toString(); } 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; } // iTunes can't handle correctly encoded ID3v2.4 numerical genres. Just use // strings until iTunes sucks less. #ifdef NO_ITUNES_HACKS int index = ID3v1::genreIndex(s); if(index != 255) setTextFrame("TCON", String::number(index)); else setTextFrame("TCON", s); #else setTextFrame("TCON", s); #endif } 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 frame; } 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); } PropertyMap ID3v2::Tag::properties() const { PropertyMap properties; for(FrameList::ConstIterator it = frameList().begin(); it != frameList().end(); ++it) { PropertyMap props = (*it)->asProperties(); properties.merge(props); } return properties; } void ID3v2::Tag::removeUnsupportedProperties(const StringList &properties) { for(StringList::ConstIterator it = properties.begin(); it != properties.end(); ++it){ if(it->startsWith("UNKNOWN/")) { String frameID = it->substr(String("UNKNOWN/").size()); if(frameID.size() != 4) continue; // invalid specification ByteVector id = frameID.data(String::Latin1); // delete all unknown frames of given type FrameList l = frameList(id); for(FrameList::ConstIterator fit = l.begin(); fit != l.end(); fit++) if (dynamic_cast<const UnknownFrame *>(*fit) != 0) removeFrame(*fit); } else if(it->size() == 4){ ByteVector id = it->data(String::Latin1); removeFrames(id); } else { ByteVector id = it->substr(0,4).data(String::Latin1); if(it->size() <= 5) continue; // invalid specification String description = it->substr(5); Frame *frame = 0; if(id == "TXXX") frame = UserTextIdentificationFrame::find(this, description); else if(id == "WXXX") frame = UserUrlLinkFrame::find(this, description); else if(id == "COMM") frame = CommentsFrame::findByDescription(this, description); else if(id == "USLT") frame = UnsynchronizedLyricsFrame::findByDescription(this, description); else if(id == "UFID") frame = UniqueFileIdentifierFrame::findByOwner(this, description); if(frame) removeFrame(frame); } } } PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps) { FrameList framesToDelete; // we split up the PropertyMap into the "normal" keys and the "complicated" ones, // which are those according to TIPL or TMCL frames. PropertyMap properties; PropertyMap tiplProperties; PropertyMap tmclProperties; Frame::splitProperties(origProps, properties, tiplProperties, tmclProperties); for(FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it){ for(FrameList::ConstIterator lit = it->second.begin(); lit != it->second.end(); ++lit){ PropertyMap frameProperties = (*lit)->asProperties(); if(it->first == "TIPL") { if (tiplProperties != frameProperties) framesToDelete.append(*lit); else tiplProperties.erase(frameProperties); } else if(it->first == "TMCL") { if (tmclProperties != frameProperties) framesToDelete.append(*lit); else tmclProperties.erase(frameProperties); } else if(!properties.contains(frameProperties)) framesToDelete.append(*lit); else properties.erase(frameProperties); } } for(FrameList::ConstIterator it = framesToDelete.begin(); it != framesToDelete.end(); ++it) removeFrame(*it); // now create remaining frames: // start with the involved people list (TIPL) if(!tiplProperties.isEmpty()) addFrame(TextIdentificationFrame::createTIPLFrame(tiplProperties)); // proceed with the musician credit list (TMCL) if(!tmclProperties.isEmpty()) addFrame(TextIdentificationFrame::createTMCLFrame(tmclProperties)); // now create the "one key per frame" frames for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) addFrame(Frame::createTextualFrame(it->first, it->second)); return PropertyMap(); // ID3 implements the complete PropertyMap interface, so an empty map is returned } ByteVector ID3v2::Tag::render() const { return render(4); } void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const { const char *unsupportedFrames[] = { "ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG", "TMOO", "TPRO", "TSOA", "TSOT", "TSST", "TSOP", 0 }; ID3v2::TextIdentificationFrame *frameTDOR = 0; ID3v2::TextIdentificationFrame *frameTDRC = 0; ID3v2::TextIdentificationFrame *frameTIPL = 0; ID3v2::TextIdentificationFrame *frameTMCL = 0; for(FrameList::Iterator it = d->frameList.begin(); it != d->frameList.end(); it++) { ID3v2::Frame *frame = *it; ByteVector frameID = frame->header()->frameID(); for(int i = 0; unsupportedFrames[i]; i++) { if(frameID == unsupportedFrames[i]) { debug("A frame that is not supported in ID3v2.3 \'" + String(frameID) + "\' has been discarded"); frame = 0; break; } } if(frame && frameID == "TDOR") { frameTDOR = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); frame = 0; } if(frame && frameID == "TDRC") { frameTDRC = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); frame = 0; } if(frame && frameID == "TIPL") { frameTIPL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); frame = 0; } if(frame && frameID == "TMCL") { frameTMCL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); frame = 0; } if(frame) { frames->append(frame); } } if(frameTDOR) { String content = frameTDOR->toString(); if(content.size() >= 4) { ID3v2::TextIdentificationFrame *frameTORY = new ID3v2::TextIdentificationFrame("TORY", String::Latin1); frameTORY->setText(content.substr(0, 4)); frames->append(frameTORY); newFrames->append(frameTORY); } } if(frameTDRC) { String content = frameTDRC->toString(); if(content.size() >= 4) { ID3v2::TextIdentificationFrame *frameTYER = new ID3v2::TextIdentificationFrame("TYER", String::Latin1); frameTYER->setText(content.substr(0, 4)); frames->append(frameTYER); newFrames->append(frameTYER); if(content.size() >= 10 && content[4] == '-' && content[7] == '-') { ID3v2::TextIdentificationFrame *frameTDAT = new ID3v2::TextIdentificationFrame("TDAT", String::Latin1); frameTDAT->setText(content.substr(8, 2) + content.substr(5, 2)); frames->append(frameTDAT); newFrames->append(frameTDAT); if(content.size() >= 16 && content[10] == 'T' && content[13] == ':') { ID3v2::TextIdentificationFrame *frameTIME = new ID3v2::TextIdentificationFrame("TIME", String::Latin1); frameTIME->setText(content.substr(11, 2) + content.substr(14, 2)); frames->append(frameTIME); newFrames->append(frameTIME); } } } } if(frameTIPL || frameTMCL) { ID3v2::TextIdentificationFrame *frameIPLS = new ID3v2::TextIdentificationFrame("IPLS", String::Latin1); StringList people; if(frameTMCL) { StringList v24People = frameTMCL->fieldList(); for(uint i = 0; i + 1 < v24People.size(); i += 2) { people.append(v24People[i]); people.append(v24People[i+1]); } } if(frameTIPL) { StringList v24People = frameTIPL->fieldList(); for(uint i = 0; i + 1 < v24People.size(); i += 2) { people.append(v24People[i]); people.append(v24People[i+1]); } } frameIPLS->setText(people); frames->append(frameIPLS); newFrames->append(frameIPLS); } } ByteVector ID3v2::Tag::render(int version) 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; if(version != 3 && version != 4) { debug("Unknown ID3v2 version, using ID3v2.4"); version = 4; } // TODO: Render the extended header. // Loop through the frames rendering them and adding them to the tagData. FrameList newFrames; newFrames.setAutoDelete(true); FrameList frameList; if(version == 4) { frameList = d->frameList; } else { downgradeFrames(&frameList, &newFrames); } for(FrameList::Iterator it = frameList.begin(); it != frameList.end(); it++) { (*it)->header()->setVersion(version); if((*it)->header()->frameID().size() != 4) { debug("A frame of unsupported or unknown type \'" + String((*it)->header()->frameID()) + "\' has been discarded"); continue; } if(!(*it)->header()->tagAlterPreservation()) 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 version and data size. d->header.setMajorVersion(version); d->header.setTagSize(tagData.size()); // TODO: This should eventually include d->footer->render(). return d->header.render() + tagData; } Latin1StringHandler const *ID3v2::Tag::latin1StringHandler() { return TagPrivate::stringHandler; } void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler) { if(handler) TagPrivate::stringHandler = handler; else TagPrivate::stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// // 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 &origData) { ByteVector data = origData; if(d->header.unsynchronisation() && d->header.majorVersion() <= 3) data = SynchData::decode(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); 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); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/id3v2/id3v2tag.h�����������������������������������������������������������0000664�0000000�0000000�00000037425�12225024651�0017713�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_ID3V2TAG_H #define TAGLIB_ID3V2TAG_H #include "tag.h" #include "tbytevector.h" #include "tstring.h" #include "tlist.h" #include "tmap.h" #include "taglib_export.h" #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<Frame *> FrameList; typedef Map<ByteVector, FrameList> FrameListMap; //! An abstraction for the ISO-8859-1 string to data encoding in ID3v2 tags. /*! * ID3v2 tag can store strings in ISO-8859-1 (Latin1), and TagLib only * supports genuine ISO-8859-1 by default. However, in practice, non * ISO-8859-1 encodings are often used instead of ISO-8859-1, such as * Windows-1252 for western languages, Shift_JIS for Japanese and so on. * * Here is an option to read such tags by subclassing this class, * reimplementing parse() and setting your reimplementation as the default * with ID3v2::Tag::setStringHandler(). * * \note Writing non-ISO-8859-1 tags is not implemented intentionally. * Use UTF-16 or UTF-8 instead. * * \see ID3v2::Tag::setStringHandler() */ class TAGLIB_EXPORT Latin1StringHandler { public: Latin1StringHandler(); virtual ~Latin1StringHandler(); /*! * 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; }; //! 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 TAGLIB_EXPORT 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); /*! * Implements the unified property interface -- export function. * This function does some work to translate the hard-specified ID3v2 * frame types into a free-form string-to-stringlist PropertyMap: * - if ID3v2 frame ID is known by Frame::frameIDToKey(), the returned * key is used * - if the frame ID is "TXXX" (user text frame), the description() is * used as key * - if the frame ID is "WXXX" (user url frame), * - if the description is empty or "URL", the key "URL" is used * - otherwise, the key "URL:<description>" is used; * - if the frame ID is "COMM" (comments frame), * - if the description is empty or "COMMENT", the key "COMMENT" * is used * - otherwise, the key "COMMENT:<description>" is used; * - if the frame ID is "USLT" (unsynchronized lyrics), * - if the description is empty or "LYRICS", the key "LYRICS" is used * - otherwise, the key "LYRICS:<description>" is used; * - if the frame ID is "TIPL" (involved peoples list), and if all the * roles defined in the frame are known in TextIdentificationFrame::involvedPeopleMap(), * then "<role>=<name>" will be contained in the returned obejct for each * - if the frame ID is "TMCL" (musician credit list), then * "PERFORMER:<instrument>=<name>" will be contained in the returned * PropertyMap for each defined musician * In any other case, the unsupportedData() of the returned object will contain * the frame's ID and, in case of a frame ID which is allowed to appear more than * once, the description, separated by a "/". * */ PropertyMap properties() const; /*! * Removes unsupported frames given by \a properties. The elements of * \a properties must be taken from properties().unsupportedData(); they * are of one of the following forms: * - a four-character frame ID, if the ID3 specification allows only one * frame with that ID (thus, the frame is uniquely determined) * - frameID + "/" + description(), when the ID is one of "TXXX", "WXXX", * "COMM", or "USLT", * - "UNKNOWN/" + frameID, for frames that could not be parsed by TagLib. * In that case, *all* unknown frames with the given ID will be removed. */ void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. * See the comments in properties(). */ PropertyMap setProperties(const PropertyMap &); /*! * Render the tag back to binary data, suitable to be written to disk. */ ByteVector render() const; /*! * Render the tag back to binary data, suitable to be written to disk. * * The \a version parameter specifies the version of the rendered * ID3v2 tag. It can be either 4 or 3. */ // BIC: combine with the above method ByteVector render(int version) const; /*! * Gets the current string handler that decides how the "Latin-1" data * will be converted to and from binary data. * * \see Latin1StringHandler */ static Latin1StringHandler const *latin1StringHandler(); /*! * Sets the string handler that decides how the "Latin-1" data will be * converted to and from binary data. * If the parameter \a handler is null, the previous handler is * released and default ISO-8859-1 handler is restored. * * \note The caller is responsible for deleting the previous handler * as needed after it is released. * * \see Latin1StringHandler */ static void setLatin1StringHandler(const Latin1StringHandler *handler); 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); void downgradeFrames(FrameList *existingFrames, FrameList *newFrames) const; private: Tag(const Tag &); Tag &operator=(const Tag &); class TagPrivate; TagPrivate *d; }; } } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/mpegfile.cpp���������������������������������������������������������������0000664�0000000�0000000�00000042224�12225024651�0017455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tagunion.h> #include <id3v2tag.h> #include <id3v2header.h> #include <id3v1tag.h> #include <apefooter.h> #include <apetag.h> #include <tdebug.h> #include <bitset> #include "mpegfile.h" #include "mpegheader.h" #include "tpropertymap.h" using namespace TagLib; namespace { enum { ID3v2Index = 0, APEIndex = 1, ID3v1Index = 2 }; } class MPEG::File::FilePrivate { public: FilePrivate(ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : ID3v2FrameFactory(frameFactory), ID3v2Location(-1), ID3v2OriginalSize(0), APELocation(-1), APEFooterLocation(-1), APEOriginalSize(0), ID3v1Location(-1), hasID3v2(false), hasID3v1(false), hasAPE(false), properties(0) { } ~FilePrivate() { delete properties; } const ID3v2::FrameFactory *ID3v2FrameFactory; long ID3v2Location; uint ID3v2OriginalSize; long APELocation; long APEFooterLocation; uint APEOriginalSize; long ID3v1Location; TagUnion 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(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } MPEG::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate(frameFactory); if(isOpen()) read(readProperties, propertiesStyle); } MPEG::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate(frameFactory); if(isOpen()) read(readProperties, propertiesStyle); } MPEG::File::~File() { delete d; } TagLib::Tag *MPEG::File::tag() const { return &d->tag; } PropertyMap MPEG::File::properties() const { // once Tag::properties() is virtual, this case distinction could actually be done // within TagUnion. if(d->hasID3v2) return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties(); if(d->hasAPE) return d->tag.access<APE::Tag>(APEIndex, false)->properties(); if(d->hasID3v1) return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->properties(); return PropertyMap(); } void MPEG::File::removeUnsupportedProperties(const StringList &properties) { if(d->hasID3v2) d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(properties); else if(d->hasAPE) d->tag.access<APE::Tag>(APEIndex, false)->removeUnsupportedProperties(properties); else if(d->hasID3v1) d->tag.access<ID3v1::Tag>(ID3v1Index, false)->removeUnsupportedProperties(properties); } PropertyMap MPEG::File::setProperties(const PropertyMap &properties) { if(d->hasID3v1) // update ID3v1 tag if it exists, but ignore the return value d->tag.access<ID3v1::Tag>(ID3v1Index, false)->setProperties(properties); return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties); } MPEG::Properties *MPEG::File::audioProperties() const { return d->properties; } bool MPEG::File::save() { return save(AllTags); } bool MPEG::File::save(int tags) { return save(tags, true); } bool MPEG::File::save(int tags, bool stripOthers) { return save(tags, stripOthers, 4); } bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version) { return save(tags, stripOthers, id3v2Version, true); } bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags) { if(tags == NoTags && stripOthers) return strip(AllTags); if(!ID3v2Tag() && !ID3v1Tag() && !APETag()) { if((d->hasID3v1 || d->hasID3v2 || d->hasAPE) && stripOthers) 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. if (duplicateTags) { // Copy the values from the tag that does exist into the new tag, // except if the existing tag is to be stripped. if((tags & ID3v2) && ID3v1Tag() && !(stripOthers && !(tags & ID3v1))) Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false); if((tags & ID3v1) && d->tag[ID3v2Index] && !(stripOthers && !(tags & ID3v2))) Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false); } bool success = true; if(ID3v2 & tags) { if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { if(!d->hasID3v2) d->ID3v2Location = 0; insert(ID3v2Tag()->render(id3v2Version), d->ID3v2Location, d->ID3v2OriginalSize); d->hasID3v2 = true; // v1 tag location has changed, update if it exists if(ID3v1Tag()) d->ID3v1Location = findID3v1(); // APE tag location has changed, update if it exists if(APETag()) findAPE(); } else if(stripOthers) success = strip(ID3v2, false) && success; } else if(d->hasID3v2 && stripOthers) success = strip(ID3v2) && success; if(ID3v1 & tags) { if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { int offset = d->hasID3v1 ? -128 : 0; seek(offset, End); writeBlock(ID3v1Tag()->render()); d->hasID3v1 = true; d->ID3v1Location = findID3v1(); } else if(stripOthers) success = strip(ID3v1) && success; } else if(d->hasID3v1 && stripOthers) success = strip(ID3v1, false) && success; // Dont save an APE-tag unless one has been created if((APE & tags) && APETag()) { if(d->hasAPE) insert(APETag()->render(), d->APELocation, d->APEOriginalSize); else { if(d->hasID3v1) { insert(APETag()->render(), d->ID3v1Location, 0); d->APEOriginalSize = APETag()->footer()->completeTagSize(); d->hasAPE = true; d->APELocation = d->ID3v1Location; d->ID3v1Location += d->APEOriginalSize; } else { seek(0, End); d->APELocation = tell(); APE::Tag *apeTag = d->tag.access<APE::Tag>(APEIndex, false); d->APEFooterLocation = d->APELocation + apeTag->footer()->completeTagSize() - APE::Footer::size(); writeBlock(APETag()->render()); d->APEOriginalSize = APETag()->footer()->completeTagSize(); d->hasAPE = true; } } } else if(d->hasAPE && stripOthers) success = strip(APE, false) && success; return success; } ID3v2::Tag *MPEG::File::ID3v2Tag(bool create) { return d->tag.access<ID3v2::Tag>(ID3v2Index, create); } ID3v1::Tag *MPEG::File::ID3v1Tag(bool create) { return d->tag.access<ID3v1::Tag>(ID3v1Index, create); } APE::Tag *MPEG::File::APETag(bool create) { return d->tag.access<APE::Tag>(APEIndex, create); } 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) d->tag.set(ID3v2Index, 0); // v1 tag location has changed, update if it exists if(ID3v1Tag()) d->ID3v1Location = findID3v1(); // APE tag location has changed, update if it exists if(APETag()) findAPE(); } if((tags & ID3v1) && d->hasID3v1) { truncate(d->ID3v1Location); d->ID3v1Location = -1; d->hasID3v1 = false; if(freeMemory) d->tag.set(ID3v1Index, 0); } if((tags & APE) && d->hasAPE) { removeBlock(d->APELocation, d->APEOriginalSize); d->APELocation = -1; d->APEFooterLocation = -1; d->hasAPE = false; if(d->hasID3v1) { if(d->ID3v1Location > d->APELocation) d->ID3v1Location -= d->APEOriginalSize; } if(freeMemory) d->tag.set(APEIndex, 0); } return true; } void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) { d->ID3v2FrameFactory = factory; } long MPEG::File::nextFrameOffset(long position) { bool foundLastSyncPattern = false; ByteVector buffer; while(true) { seek(position); buffer = readBlock(bufferSize()); if(buffer.size() <= 0) return -1; if(foundLastSyncPattern && secondSynchByte(buffer[0])) return position - 1; for(uint i = 0; i < buffer.size() - 1; i++) { if(uchar(buffer[i]) == 0xff && secondSynchByte(buffer[i + 1])) return position + i; } foundLastSyncPattern = uchar(buffer[buffer.size() - 1]) == 0xff; position += buffer.size(); } } long MPEG::File::previousFrameOffset(long position) { bool foundFirstSyncPattern = false; ByteVector buffer; while (position > 0) { long size = ulong(position) < bufferSize() ? position : bufferSize(); position -= size; seek(position); buffer = readBlock(size); if(buffer.size() <= 0) break; if(foundFirstSyncPattern && uchar(buffer[buffer.size() - 1]) == 0xff) return position + buffer.size() - 1; for(int i = buffer.size() - 2; i >= 0; i--) { if(uchar(buffer[i]) == 0xff && secondSynchByte(buffer[i + 1])) return position + i; } foundFirstSyncPattern = secondSynchByte(buffer[0]); } return -1; } long MPEG::File::firstFrameOffset() { long position = 0; if(ID3v2Tag()) position = d->ID3v2Location + ID3v2Tag()->header()->completeTagSize(); return nextFrameOffset(position); } long MPEG::File::lastFrameOffset() { return previousFrameOffset(ID3v1Tag() ? d->ID3v1Location - 1 : length()); } bool MPEG::File::hasID3v1Tag() const { return d->hasID3v1; } bool MPEG::File::hasID3v2Tag() const { return d->hasID3v2; } bool MPEG::File::hasAPETag() const { return d->hasAPE; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void MPEG::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { // Look for an ID3v2 tag d->ID3v2Location = findID3v2(); if(d->ID3v2Location >= 0) { d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); if(ID3v2Tag()->header()->tagSize() <= 0) d->tag.set(ID3v2Index, 0); else d->hasID3v2 = true; } // Look for an ID3v1 tag d->ID3v1Location = findID3v1(); if(d->ID3v1Location >= 0) { d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); d->hasID3v1 = true; } // Look for an APE tag findAPE(); if(d->APELocation >= 0) { d->tag.set(APEIndex, new APE::Tag(this, d->APEFooterLocation)); d->APEOriginalSize = APETag()->footer()->completeTagSize(); d->hasAPE = true; } if(readProperties) d->properties = new Properties(this, propertiesStyle); // Make sure that we have our default tag types available. ID3v2Tag(true); ID3v1Tag(true); } 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; } void MPEG::File::findAPE() { if(isValid()) { seek(d->hasID3v1 ? -160 : -32, End); long p = tell(); if(readBlock(8) == APE::Tag::fileIdentifier()) { d->APEFooterLocation = p; seek(d->APEFooterLocation); APE::Footer footer(readBlock(APE::Footer::size())); d->APELocation = d->APEFooterLocation - footer.completeTagSize() + APE::Footer::size(); return; } } d->APELocation = -1; d->APEFooterLocation = -1; } bool MPEG::File::secondSynchByte(char byte) { std::bitset<8> b(byte); // check to see if the byte matches 111xxxxx return b.test(7) && b.test(6) && b.test(5); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/mpegfile.h�����������������������������������������������������������������0000664�0000000�0000000�00000035251�12225024651�0017124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MPEGFILE_H #define TAGLIB_MPEGFILE_H #include "taglib_export.h" #include "tfile.h" #include "tag.h" #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 TAGLIB_EXPORT File : public TagLib::File { public: /*! * This set of flags is used for various operations and is suitable for * being OR-ed together. */ enum TagTypes { //! Empty set. Matches no tag types. NoTags = 0x0000, //! Matches ID3v1 tags. ID3v1 = 0x0001, //! Matches ID3v2 tags. ID3v2 = 0x0002, //! Matches APE tags. APE = 0x0004, //! Matches all tag types. AllTags = 0xffff }; /*! * Constructs an MPEG file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. * * \deprecated This constructor will be dropped in favor of the one below * in a future version. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an MPEG file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * If this file contains and ID3v2 tag the frames will be created using * \a frameFactory. * * \note In the current implementation, \a propertiesStyle is ignored. */ // BIC: merge with the above constructor File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an MPEG file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * If this file contains and ID3v2 tag the frames will be created using * \a frameFactory. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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; /*! * Implements the reading part of the unified property interface. * If the file contains more than one tag, only the * first one (in the order ID3v2, APE, ID3v1) will be converted to the * PropertyMap. */ PropertyMap properties() const; void removeUnsupportedProperties(const StringList &properties); /*! * Implements the writing part of the unified tag dictionary interface. * In order to avoid problems with deprecated tag formats, this method * always creates an ID3v2 tag if necessary. * If an ID3v1 tag exists, it will be updated as well, within the * limitations of that format. * The returned PropertyMap refers to the ID3v2 tag only. */ PropertyMap setProperties(const PropertyMap &); /*! * 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); /*! * 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. * * If \a stripOthers is true 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. */ // BIC: combine with the above method bool save(int tags, bool stripOthers); /*! * 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. * * If \a stripOthers is true 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. * * The \a id3v2Version parameter specifies the version of the saved * ID3v2 tag. It can be either 4 or 3. */ // BIC: combine with the above method bool save(int tags, bool stripOthers, int id3v2Version); /*! * 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. * * If \a stripOthers is true 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. * * The \a id3v2Version parameter specifies the version of the saved * ID3v2 tag. It can be either 4 or 3. * * If \a duplicateTags is true and at least one tag -- ID3v1 or ID3v2 -- * exists this will duplicate its content into the other tag. */ // BIC: combine with the above method bool save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags); /*! * Returns a pointer to the ID3v2 tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file * on disk actually has an ID3v2 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v2Tag() */ ID3v2::Tag *ID3v2Tag(bool create = false); /*! * Returns a pointer to the ID3v1 tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file * on disk actually has an ID3v1 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v1Tag() */ ID3v1::Tag *ID3v1Tag(bool create = false); /*! * Returns a pointer to the APE tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an APE tag. Use hasAPETag() to check if the file * on disk actually has an APE tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasAPETag() */ 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(); /*! * Returns whether or not the file on disk actually has an ID3v1 tag. * * \see ID3v1Tag() */ bool hasID3v1Tag() const; /*! * Returns whether or not the file on disk actually has an ID3v2 tag. * * \see ID3v2Tag() */ bool hasID3v2Tag() const; /*! * Returns whether or not the file on disk actually has an APE tag. * * \see APETag() */ bool hasAPETag() const; private: File(const File &); File &operator=(const File &); void read(bool readProperties, Properties::ReadStyle propertiesStyle); long findID3v2(); long findID3v1(); void 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 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/mpegheader.cpp�������������������������������������������������������������0000664�0000000�0000000�00000016113�12225024651�0017764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <bitset> #include <tbytevector.h> #include <tstring.h> #include <tdebug.h> #include "trefcounter.h" #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), samplesPerFrame(0) {} bool isValid; Version version; int layer; bool protectionEnabled; int bitrate; int sampleRate; bool isPadded; ChannelMode channelMode; bool isCopyrighted; bool isOriginal; int frameLength; int samplesPerFrame; }; //////////////////////////////////////////////////////////////////////////////// // 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; } int MPEG::Header::samplesPerFrame() const { return d->samplesPerFrame; } 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 match MPEG synch."); return; } std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(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 match 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[3]) & 0xC0) >> 6); // TODO: Add mode extension for completeness d->isOriginal = flags[2]; d->isCopyrighted = flags[3]; d->isPadded = flags[9]; // 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); // Samples per frame static const int samplesPerFrame[3][2] = { // MPEG1, 2/2.5 { 384, 384 }, // Layer I { 1152, 1152 }, // Layer II { 1152, 576 } // Layer III }; d->samplesPerFrame = samplesPerFrame[layerIndex][versionIndex]; // Now that we're done parsing, set this to be a valid frame. d->isValid = true; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/mpegheader.h���������������������������������������������������������������0000664�0000000�0000000�00000011002�12225024651�0017421�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MPEGHEADER_H #define TAGLIB_MPEGHEADER_H #include "taglib_export.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 * <a href="http://www.mp3-tech.org/programmer/frame_header.html">this</a> * document as a reference. */ class TAGLIB_EXPORT 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; /*! * Returns the number of frames per sample. */ int samplesPerFrame() const; /*! * Makes a shallow copy of the header. */ Header &operator=(const Header &h); private: void parse(const ByteVector &data); class HeaderPrivate; HeaderPrivate *d; }; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/mpegproperties.cpp���������������������������������������������������������0000664�0000000�0000000�00000015566�12225024651�0020743�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tstring.h> #include "mpegproperties.h" #include "mpegfile.h" #include "xingheader.h" using namespace TagLib; class MPEG::Properties::PropertiesPrivate { public: PropertiesPrivate(File *f, ReadStyle s) : file(f), xingHeader(0), style(s), length(0), bitrate(0), sampleRate(0), channels(0), layer(0), version(Header::Version1), channelMode(Header::Stereo), protectionEnabled(false), isCopyrighted(false), isOriginal(false) {} ~PropertiesPrivate() { delete xingHeader; } File *file; XingHeader *xingHeader; ReadStyle style; int length; int bitrate; int sampleRate; int channels; int layer; Header::Version version; Header::ChannelMode channelMode; bool protectionEnabled; 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; } const MPEG::XingHeader *MPEG::Properties::xingHeader() const { return d->xingHeader; } MPEG::Header::Version MPEG::Properties::version() const { return d->version; } int MPEG::Properties::layer() const { return d->layer; } bool MPEG::Properties::protectionEnabled() const { return d->protectionEnabled; } 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); d->xingHeader = new XingHeader(d->file->readBlock(16)); // Read the length and the bitrate from the Xing header. if(d->xingHeader->isValid() && firstHeader.sampleRate() > 0 && d->xingHeader->totalFrames() > 0) { double timePerFrame = double(firstHeader.samplesPerFrame()) / firstHeader.sampleRate(); double length = timePerFrame * d->xingHeader->totalFrames(); d->length = int(length); d->bitrate = d->length > 0 ? (int)(d->xingHeader->totalSize() * 8 / length / 1000) : 0; } else { // Since there was no valid Xing header found, we hope that we're in a constant // bitrate file. delete d->xingHeader; d->xingHeader = 0; // TODO: Make this more robust with audio property detection for VBR without a // Xing header. 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->protectionEnabled = firstHeader.protectionEnabled(); d->channelMode = firstHeader.channelMode(); d->isCopyrighted = firstHeader.isCopyrighted(); d->isOriginal = firstHeader.isOriginal(); } ������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/mpegproperties.h�����������������������������������������������������������0000664�0000000�0000000�00000007173�12225024651�0020403�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MPEGPROPERTIES_H #define TAGLIB_MPEGPROPERTIES_H #include "taglib_export.h" #include "audioproperties.h" #include "mpegheader.h" namespace TagLib { namespace MPEG { class File; class XingHeader; //! An implementation of audio property reading for MP3 /*! * This reads the data from an MPEG Layer III stream found in the * AudioProperties API. */ class TAGLIB_EXPORT 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 a pointer to the XingHeader if one exists or null if no * XingHeader was found. */ const XingHeader *xingHeader() 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 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/xingheader.cpp�������������������������������������������������������������0000664�0000000�0000000�00000006523�12225024651�0020005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tstring.h> #include <tdebug.h> #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.startsWith("Xing") && !data.startsWith("Info")) return; // If the XingHeader doesn't contain the number of frames and the total stream // info it's invalid. if(!(data[7] & 0x01)) { debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total number of frames."); return; } if(!(data[7] & 0x02)) { debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total stream size."); return; } d->frames = data.toUInt(8U); d->size = data.toUInt(12U); d->valid = true; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/mpeg/xingheader.h���������������������������������������������������������������0000664�0000000�0000000�00000007212�12225024651�0017446�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_XINGHEADER_H #define TAGLIB_XINGHEADER_H #include "mpegheader.h" #include "taglib_export.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 * <a href="http://home.pcisys.net/~melanson/codecs/mp3extensions.txt">this text</a> * and the XMMS sources as references. */ class TAGLIB_EXPORT 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 valid * 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 */ // BIC: rename to offset() static int xingHeaderOffset(TagLib::MPEG::Header::Version v, TagLib::MPEG::Header::ChannelMode c); private: XingHeader(const XingHeader &); XingHeader &operator=(const XingHeader &); void parse(const ByteVector &data); class XingHeaderPrivate; XingHeaderPrivate *d; }; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015001�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/flac/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015706�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/flac/oggflacfile.cpp��������������������������������������������������������0000664�0000000�0000000�00000016405�12225024651�0020662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2004-2005 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tstring.h> #include <tdebug.h> #include <tpropertymap.h> #include <xiphcomment.h> #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(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } Ogg::FLAC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } Ogg::FLAC::File::~File() { delete d; } Ogg::XiphComment *Ogg::FLAC::File::tag() const { return d->comment; } PropertyMap Ogg::FLAC::File::properties() const { return d->comment->properties(); } PropertyMap Ogg::FLAC::File::setProperties(const PropertyMap &properties) { return d->comment->setProperties(properties); } Properties *Ogg::FLAC::File::audioProperties() const { return d->properties; } bool Ogg::FLAC::File::save() { d->xiphCommentData = d->comment->render(false); // 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(); } bool Ogg::FLAC::File::hasXiphComment() const { return d->hasXiphComment; } //////////////////////////////////////////////////////////////////////////////// // 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 = 0; long overhead = 0; ByteVector metadataHeader = packet(ipacket); if(metadataHeader.isNull()) return; ByteVector header; if (!metadataHeader.startsWith("fLaC")) { // FLAC 1.1.2+ if (metadataHeader.mid(1,4) != "FLAC") return; if (metadataHeader[5] != 1) return; // not version 1 metadataHeader = metadataHeader.mid(13); } else { // FLAC 1.1.0 & 1.1.1 metadataHeader = packet(++ipacket); if(metadataHeader.isNull()) return; } 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) != 0; uint length = header.toUInt(1, 3, true); 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); if(metadataHeader.isNull()) return; header = metadataHeader.mid(0, 4); blockType = header[0] & 0x7f; lastBlock = (header[0] & 0x80) != 0; length = header.toUInt(1, 3, true); 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; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/flac/oggflacfile.h����������������������������������������������������������0000664�0000000�0000000�00000013254�12225024651�0020326�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_OGGFLACFILE_H #define TAGLIB_OGGFLACFILE_H #include "taglib_export.h" #include "oggfile.h" #include "xiphcomment.h" #include "flacproperties.h" 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 TAGLIB_EXPORT File : public Ogg::File { public: /*! * Constructs an Ogg/FLAC file from \a file. If \a readProperties is true * the file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an Ogg/FLAC file from \a stream. If \a readProperties is true * the file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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. * * \note This always returns a valid pointer regardless of whether or not * the file on disk has a XiphComment. Use hasXiphComment() to check if * the file on disk actually has a XiphComment. * * \note The Tag <b>is still</b> owned by the FLAC::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasXiphComment() */ 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; /*! * Implements the unified property interface -- export function. * This forwards directly to XiphComment::properties(). */ PropertyMap properties() const; /*! * Implements the unified tag dictionary interface -- import function. * Like properties(), this is a forwarder to the file's XiphComment. */ PropertyMap setProperties(const PropertyMap &); /*! * 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(); /*! * Returns whether or not the file on disk actually has a XiphComment. * * \see tag() */ bool hasXiphComment() const; 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 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/oggfile.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000033167�12225024651�0017133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevectorlist.h> #include <tmap.h> #include <tstring.h> #include <tdebug.h> #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<Page *> pages; PageHeader *firstPageHeader; PageHeader *lastPageHeader; std::vector< List<int> > packetToPageMap; Map<int, ByteVector> dirtyPackets; List<int> 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<int>::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<int> pageGroup; for(List<int>::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(FileName file) : TagLib::File(file) { d = new FilePrivate; } Ogg::File::File(IOStream *stream) : TagLib::File(stream) { 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<int>()); d->packetToPageMap[currentPacket].append(d->pages.size() - 1); } return true; } void Ogg::File::writePageGroup(const List<int> &thePageGroup) { if(thePageGroup.isEmpty()) return; // pages in the pageGroup and packets must be equivalent // (originalSize and size of packets would not work together), // therefore we sometimes have to add pages to the group List<int> pageGroup(thePageGroup); while (!d->pages[pageGroup.back()]->header()->lastPacketCompleted()) { if (d->currentPage->header()->pageSequenceNumber() == pageGroup.back()) { if (nextPage() == false) { debug("broken ogg file"); return; } pageGroup.append(d->currentPage->header()->pageSequenceNumber()); } else { pageGroup.append(pageGroup.back() + 1); } } 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<int>::ConstIterator it = pageGroup.begin(); it != pageGroup.end(); ++it) { uint firstPacket = d->pages[*it]->firstPacketIndex(); uint lastPacket = firstPacket + d->pages[*it]->packetCount() - 1; List<int>::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<Page *> pages = Page::paginate(packets, Page::SinglePagePerGroup, d->streamSerialNumber, pageGroup.front(), continued, completed); List<Page *> renumberedPages; // Correct the page numbering of following pages if (pages.back()->header()->pageSequenceNumber() != pageGroup.back()) { // TODO: change the internal data structure so that we don't need to hold the // complete file in memory (is unavoidable at the moment) // read the complete stream while(!d->currentPage->header()->lastPageOfStream()) { if(nextPage() == false) { debug("broken ogg file"); break; } } // create a gap for the new pages int numberOfNewPages = pages.back()->header()->pageSequenceNumber() - pageGroup.back(); List<Page *>::Iterator pageIter = d->pages.begin(); for(int i = 0; i < pageGroup.back(); i++) { if(pageIter != d->pages.end()) { ++pageIter; } else { debug("Ogg::File::writePageGroup() -- Page sequence is broken in original file."); break; } } ++pageIter; for(; pageIter != d->pages.end(); ++pageIter) { Ogg::Page *newPage = (*pageIter)->getCopyWithNewPageSequenceNumber( (*pageIter)->header()->pageSequenceNumber() + numberOfNewPages); ByteVector data; data.append(newPage->render()); insert(data, newPage->fileOffset(), data.size()); renumberedPages.append(newPage); } } // insert the new data ByteVector data; for(List<Page *>::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. // First step: Pages that contain the comment data for(List<Page *>::ConstIterator it = pages.begin(); it != pages.end(); ++it) { const unsigned int index = (*it)->header()->pageSequenceNumber(); if(index < d->pages.size()) { delete d->pages[index]; d->pages[index] = *it; } else if(index == d->pages.size()) { d->pages.append(*it); } else { // oops - there's a hole in the sequence debug("Ogg::File::writePageGroup() -- Page sequence is broken."); } } // Second step: the renumbered pages for(List<Page *>::ConstIterator it = renumberedPages.begin(); it != renumberedPages.end(); ++it) { const unsigned int index = (*it)->header()->pageSequenceNumber(); if(index < d->pages.size()) { delete d->pages[index]; d->pages[index] = *it; } else if(index == d->pages.size()) { d->pages.append(*it); } else { // oops - there's a hole in the sequence debug("Ogg::File::writePageGroup() -- Page sequence is broken."); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/oggfile.h�������������������������������������������������������������������0000664�0000000�0000000�00000010416�12225024651�0016570�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "taglib_export.h" #include "tfile.h" #include "tbytevectorlist.h" #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 TAGLIB_EXPORT 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: /*! * Constructs an Ogg file from \a file. * * \note This constructor is protected since Ogg::File shouldn't be * instantiated directly but rather should be used through the codec * specific subclasses. */ File(FileName file); /*! * Constructs an Ogg file from \a stream. * * \note This constructor is protected since Ogg::File shouldn't be * instantiated directly but rather should be used through the codec * specific subclasses. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. */ File(IOStream *stream); 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<int> &group); class FilePrivate; FilePrivate *d; }; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/oggpage.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000023711�12225024651�0017122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include "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<int> 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 there is more than one page and 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(packetCount() > 1 && ((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<int> packetSizes = d->header.packetSizes(); List<int>::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 *> Ogg::Page::paginate(const ByteVectorList &packets, PaginationStrategy strategy, uint streamSerialNumber, int firstPage, bool firstPacketContinued, bool lastPacketCompleted, bool containsLastPacket) { List<Page *> l; int totalSize = 0; for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) totalSize += (*it).size(); // Handle creation of multiple pages with appropriate pagination. if(strategy == Repaginate || totalSize + packets.size() > 255 * 255) { // SPLITSIZE must be a multiple of 255 in order to get the lacing values right // create pages of about 8KB each #define SPLITSIZE (32*255) int pageIndex = 0; for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { bool continued = false; // mark very first packet? if(firstPacketContinued && it==packets.begin()) { continued = true; } // append to buf ByteVector packetBuf; packetBuf.append(*it); while(packetBuf.size() > SPLITSIZE) { // output a Page ByteVector packetForOnePage; packetForOnePage.resize(SPLITSIZE); std::copy(packetBuf.begin(), packetBuf.begin() + SPLITSIZE, packetForOnePage.begin()); ByteVectorList packetList; packetList.append(packetForOnePage); Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, false, false); l.append(p); pageIndex++; continued = true; packetBuf = packetBuf.mid(SPLITSIZE); } ByteVectorList::ConstIterator jt = it; ++jt; bool lastPacketInList = (jt == packets.end()); // output a page for the rest (we output one packet per page, so this one should be completed) ByteVectorList packetList; packetList.append(packetBuf); bool isVeryLastPacket = false; if(containsLastPacket) { // mark the very last output page as last of stream ByteVectorList::ConstIterator jt = it; ++jt; if(jt == packets.end()) { isVeryLastPacket = true; } } Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, lastPacketInList ? lastPacketCompleted : true, isVeryLastPacket); pageIndex++; l.append(p); } } else { Page *p = new Page(packets, streamSerialNumber, firstPage, firstPacketContinued, lastPacketCompleted, containsLastPacket); l.append(p); } return l; } Ogg::Page* Ogg::Page::getCopyWithNewPageSequenceNumber(int sequenceNumber) { Page *pResultPage = NULL; // TODO: a copy constructor would be helpful if(d->file == 0) { pResultPage = new Page( d->packets, d->header.streamSerialNumber(), sequenceNumber, d->header.firstPacketContinued(), d->header.lastPacketCompleted(), d->header.lastPageOfStream()); } else { pResultPage = new Page(d->file, d->fileOffset); pResultPage->d->header.setPageSequenceNumber(sequenceNumber); } return pResultPage; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// Ogg::Page::Page(const ByteVectorList &packets, uint streamSerialNumber, int pageNumber, bool firstPacketContinued, bool lastPacketCompleted, bool containsLastPacket) { d = new PagePrivate; ByteVector data; List<int> 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); } �������������������������������������������������������taglib-1.9.1/taglib/ogg/oggpage.h�������������������������������������������������������������������0000664�0000000�0000000�00000017065�12225024651�0016574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_OGGPAGE_H #define TAGLIB_OGGPAGE_H #include "taglib_export.h" #include "tbytevectorlist.h" 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 TAGLIB_EXPORT 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 a copy of the page with \a sequenceNumber set as sequence number. * * \see header() * \see PageHeader::setPageSequenceNumber() */ Page* getCopyWithNewPageSequenceNumber(int sequenceNumber); /*! * 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<T>::setAutoDelete(true) to set these pages to be * automatically deleted when this list passes out of scope. * * \see PaginationStrategy * \see List::setAutoDelete() */ static List<Page *> 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 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/oggpageheader.cpp�����������������������������������������������������������0000664�0000000�0000000�00000020236�12225024651�0020272�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <stdlib.h> #include <bitset> #include <tstring.h> #include <tdebug.h> #include <taglib.h> #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<int> 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<int> Ogg::PageHeader::packetSizes() const { return d->packetSizes; } void Ogg::PageHeader::setPacketSizes(const List<int> &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.startsWith("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.toLongLong(6, false); d->streamSerialNumber = data.toUInt(14, false); d->pageSequenceNumber = data.toUInt(18, 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 corresponding 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<int> sizes = d->packetSizes; for(List<int>::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; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/oggpageheader.h�������������������������������������������������������������0000664�0000000�0000000�00000016630�12225024651�0017742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_OGGPAGEHEADER_H #define TAGLIB_OGGPAGEHEADER_H #include "tlist.h" #include "tbytevector.h" #include "taglib_export.h" 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 TAGLIB_EXPORT 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<int> 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<int> &sizes); /*! * Some packets can be <i>continued</i> 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 ��������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/opus/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015767�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/opus/opusfile.cpp�����������������������������������������������������������0000664�0000000�0000000�00000010224�12225024651�0020320�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <bitset> #include <tstring.h> #include <tdebug.h> #include <tpropertymap.h> #include "opusfile.h" using namespace TagLib; using namespace TagLib::Ogg; class Opus::File::FilePrivate { public: FilePrivate() : comment(0), properties(0) {} ~FilePrivate() { delete comment; delete properties; } Ogg::XiphComment *comment; Properties *properties; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// Opus::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(file), d(new FilePrivate()) { if(isOpen()) read(readProperties, propertiesStyle); } Opus::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(stream), d(new FilePrivate()) { if(isOpen()) read(readProperties, propertiesStyle); } Opus::File::~File() { delete d; } Ogg::XiphComment *Opus::File::tag() const { return d->comment; } PropertyMap Opus::File::properties() const { return d->comment->properties(); } PropertyMap Opus::File::setProperties(const PropertyMap &properties) { return d->comment->setProperties(properties); } Opus::Properties *Opus::File::audioProperties() const { return d->properties; } bool Opus::File::save() { if(!d->comment) d->comment = new Ogg::XiphComment; setPacket(1, ByteVector("OpusTags", 8) + d->comment->render(false)); return Ogg::File::save(); } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void Opus::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { ByteVector opusHeaderData = packet(0); if(!opusHeaderData.startsWith("OpusHead")) { setValid(false); debug("Opus::File::read() -- invalid Opus identification header"); return; } ByteVector commentHeaderData = packet(1); if(!commentHeaderData.startsWith("OpusTags")) { setValid(false); debug("Opus::File::read() -- invalid Opus tags header"); return; } d->comment = new Ogg::XiphComment(commentHeaderData.mid(8)); if(readProperties) d->properties = new Properties(this, propertiesStyle); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/opus/opusfile.h�������������������������������������������������������������0000664�0000000�0000000�00000011311�12225024651�0017763�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_OPUSFILE_H #define TAGLIB_OPUSFILE_H #include "oggfile.h" #include "xiphcomment.h" #include "opusproperties.h" namespace TagLib { namespace Ogg { //! A namespace containing classes for Opus metadata namespace Opus { //! An implementation of Ogg::File with Opus specific methods /*! * This is the central class in the Ogg Opus 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 Opus specifically. */ class TAGLIB_EXPORT File : public Ogg::File { public: /*! * Constructs an Opus file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an Opus file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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; /*! * Implements the unified property interface -- export function. * This forwards directly to XiphComment::properties(). */ PropertyMap properties() const; /*! * Implements the unified tag dictionary interface -- import function. * Like properties(), this is a forwarder to the file's XiphComment. */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the Opus::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; }; } } } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/opus/opusproperties.cpp�����������������������������������������������������0000664�0000000�0000000�00000011414�12225024651�0021577�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include <oggpageheader.h> #include "opusproperties.h" #include "opusfile.h" using namespace TagLib; using namespace TagLib::Ogg; class Opus::Properties::PropertiesPrivate { public: PropertiesPrivate(File *f, ReadStyle s) : file(f), style(s), length(0), inputSampleRate(0), channels(0), opusVersion(0) {} File *file; ReadStyle style; int length; int inputSampleRate; int channels; int opusVersion; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// Opus::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(file, style); read(); } Opus::Properties::~Properties() { delete d; } int Opus::Properties::length() const { return d->length; } int Opus::Properties::bitrate() const { return 0; } int Opus::Properties::sampleRate() const { // Opus can decode any stream at a sample rate of 8, 12, 16, 24, or 48 kHz, // so there is no single sample rate. Let's assume it's the highest // possible. return 48000; } int Opus::Properties::channels() const { return d->channels; } int Opus::Properties::inputSampleRate() const { return d->inputSampleRate; } int Opus::Properties::opusVersion() const { return d->opusVersion; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void Opus::Properties::read() { // Get the identification header from the Ogg implementation. // http://tools.ietf.org/html/draft-terriberry-oggopus-01#section-5.1 ByteVector data = d->file->packet(0); // *Magic Signature* uint pos = 8; // *Version* (8 bits, unsigned) d->opusVersion = uchar(data.at(pos)); pos += 1; // *Output Channel Count* 'C' (8 bits, unsigned) d->channels = uchar(data.at(pos)); pos += 1; // *Pre-skip* (16 bits, unsigned, little endian) const ushort preSkip = data.toUShort(pos, false); pos += 2; // *Input Sample Rate* (32 bits, unsigned, little endian) d->inputSampleRate = data.toUInt(pos, false); pos += 4; // *Output Gain* (16 bits, signed, little endian) pos += 2; // *Channel Mapping Family* (8 bits, unsigned) pos += 1; 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->length = (int) ((end - start - preSkip) / 48000); else { debug("Opus::Properties::read() -- The PCM values for the start or " "end of this file was incorrect."); } } else debug("Opus::Properties::read() -- Could not find valid first and last Ogg pages."); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/opus/opusproperties.h�������������������������������������������������������0000664�0000000�0000000�00000006560�12225024651�0021252�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_OPUSPROPERTIES_H #define TAGLIB_OPUSPROPERTIES_H #include "audioproperties.h" namespace TagLib { namespace Ogg { namespace Opus { class File; //! An implementation of audio property reading for Ogg Opus /*! * This reads the data from an Ogg Opus stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of Opus::Properties with the data read from the * Opus::File \a file. */ Properties(File *file, ReadStyle style = Average); /*! * Destroys this Opus::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; /*! * The Opus codec supports decoding at multiple sample rates, there is no * single sample rate of the encoded stream. This returns the sample rate * of the original audio stream. */ int inputSampleRate() const; /*! * Returns the Opus version, currently "0" (as specified by the spec). */ int opusVersion() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(); class PropertiesPrivate; PropertiesPrivate *d; }; } } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/speex/����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0016125�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/speex/speexfile.cpp���������������������������������������������������������0000664�0000000�0000000�00000007762�12225024651�0020631�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <bitset> #include <tstring.h> #include <tdebug.h> #include <tpropertymap.h> #include "speexfile.h" using namespace TagLib; using namespace TagLib::Ogg; class Speex::File::FilePrivate { public: FilePrivate() : comment(0), properties(0) {} ~FilePrivate() { delete comment; delete properties; } Ogg::XiphComment *comment; Properties *properties; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// Speex::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } Speex::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } Speex::File::~File() { delete d; } Ogg::XiphComment *Speex::File::tag() const { return d->comment; } PropertyMap Speex::File::properties() const { return d->comment->properties(); } PropertyMap Speex::File::setProperties(const PropertyMap &properties) { return d->comment->setProperties(properties); } Speex::Properties *Speex::File::audioProperties() const { return d->properties; } bool Speex::File::save() { if(!d->comment) d->comment = new Ogg::XiphComment; setPacket(1, d->comment->render()); return Ogg::File::save(); } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void Speex::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { ByteVector speexHeaderData = packet(0); if(!speexHeaderData.startsWith("Speex ")) { debug("Speex::File::read() -- invalid Speex identification header"); return; } ByteVector commentHeaderData = packet(1); d->comment = new Ogg::XiphComment(commentHeaderData); if(readProperties) d->properties = new Properties(this, propertiesStyle); } ��������������taglib-1.9.1/taglib/ogg/speex/speexfile.h�����������������������������������������������������������0000664�0000000�0000000�00000011324�12225024651�0020263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_SPEEXFILE_H #define TAGLIB_SPEEXFILE_H #include "oggfile.h" #include "xiphcomment.h" #include "speexproperties.h" namespace TagLib { namespace Ogg { //! A namespace containing classes for Speex metadata namespace Speex { //! An implementation of Ogg::File with Speex specific methods /*! * This is the central class in the Ogg Speex 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 Speex specifically. */ class TAGLIB_EXPORT File : public Ogg::File { public: /*! * Constructs a Speex file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs a Speex file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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; /*! * Implements the unified property interface -- export function. * This forwards directly to XiphComment::properties(). */ PropertyMap properties() const; /*! * Implements the unified tag dictionary interface -- import function. * Like properties(), this is a forwarder to the file's XiphComment. */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the Speex::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; }; } } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/speex/speexproperties.cpp���������������������������������������������������0000664�0000000�0000000�00000012366�12225024651�0022102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include <oggpageheader.h> #include "speexproperties.h" #include "speexfile.h" using namespace TagLib; using namespace TagLib::Ogg; class Speex::Properties::PropertiesPrivate { public: PropertiesPrivate(File *f, ReadStyle s) : file(f), style(s), length(0), bitrate(0), sampleRate(0), channels(0), speexVersion(0), vbr(false), mode(0) {} File *file; ReadStyle style; int length; int bitrate; int sampleRate; int channels; int speexVersion; bool vbr; int mode; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// Speex::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(file, style); read(); } Speex::Properties::~Properties() { delete d; } int Speex::Properties::length() const { return d->length; } int Speex::Properties::bitrate() const { return int(float(d->bitrate) / float(1000) + 0.5); } int Speex::Properties::sampleRate() const { return d->sampleRate; } int Speex::Properties::channels() const { return d->channels; } int Speex::Properties::speexVersion() const { return d->speexVersion; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void Speex::Properties::read() { // Get the identification header from the Ogg implementation. ByteVector data = d->file->packet(0); uint pos = 28; // speex_version_id; /**< Version for Speex (for checking compatibility) */ d->speexVersion = data.toUInt(pos, false); pos += 4; // header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */ pos += 4; // rate; /**< Sampling rate used */ d->sampleRate = data.toUInt(pos, false); pos += 4; // mode; /**< Mode used (0 for narrowband, 1 for wideband) */ d->mode = data.toUInt(pos, false); pos += 4; // mode_bitstream_version; /**< Version ID of the bit-stream */ pos += 4; // nb_channels; /**< Number of channels encoded */ d->channels = data.toUInt(pos, false); pos += 4; // bitrate; /**< Bit-rate used */ d->bitrate = data.toUInt(pos, false); pos += 4; // frame_size; /**< Size of frames */ // unsigned int frameSize = data.mid(pos, 4).toUInt(false); pos += 4; // vbr; /**< 1 for a VBR encoding, 0 otherwise */ d->vbr = data.toUInt(pos, false) == 1; pos += 4; // frames_per_packet; /**< Number of frames stored per Ogg packet */ // unsigned int framesPerPacket = data.mid(pos, 4).toUInt(false); 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 = (int) ((end - start) / (long long) d->sampleRate); else debug("Speex::Properties::read() -- Either the PCM values for the start or " "end of this file was incorrect or the sample rate is zero."); } else debug("Speex::Properties::read() -- Could not find valid first and last Ogg pages."); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/speex/speexproperties.h�����������������������������������������������������0000664�0000000�0000000�00000006157�12225024651�0021550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org (original Vorbis implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_SPEEXPROPERTIES_H #define TAGLIB_SPEEXPROPERTIES_H #include "audioproperties.h" namespace TagLib { namespace Ogg { namespace Speex { class File; //! An implementation of audio property reading for Ogg Speex /*! * This reads the data from an Ogg Speex stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of Speex::Properties with the data read from the * Speex::File \a file. */ Properties(File *file, ReadStyle style = Average); /*! * Destroys this Speex::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; /*! * Returns the Speex version, currently "0" (as specified by the spec). */ int speexVersion() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(); class PropertiesPrivate; PropertiesPrivate *d; }; } } } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/vorbis/���������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0016305�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/vorbis/vorbisfile.cpp�������������������������������������������������������0000664�0000000�0000000�00000010176�12225024651�0021162�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <bitset> #include <tstring.h> #include <tdebug.h> #include <tpropertymap.h> #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(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } Vorbis::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : Ogg::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } Vorbis::File::~File() { delete d; } Ogg::XiphComment *Vorbis::File::tag() const { return d->comment; } PropertyMap Vorbis::File::properties() const { return d->comment->properties(); } PropertyMap Vorbis::File::setProperties(const PropertyMap &properties) { return d->comment->setProperties(properties); } 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); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/vorbis/vorbisfile.h���������������������������������������������������������0000664�0000000�0000000�00000012100�12225024651�0020614�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_VORBISFILE_H #define TAGLIB_VORBISFILE_H #include "taglib_export.h" #include "oggfile.h" #include "xiphcomment.h" #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 TAGLIB_EXPORT File : public Ogg::File { public: /*! * Constructs a Vorbis file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs a Vorbis file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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; /*! * Implements the unified property interface -- export function. * This forwards directly to XiphComment::properties(). */ PropertyMap properties() const; /*! * Implements the unified tag dictionary interface -- import function. * Like properties(), this is a forwarder to the file's XiphComment. */ PropertyMap setProperties(const PropertyMap &); /*! * 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 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/vorbis/vorbisproperties.cpp�������������������������������������������������0000664�0000000�0000000�00000012233�12225024651�0022433�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include <oggpageheader.h> #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); uint pos = 0; if(data.mid(pos, 7) != vorbisSetupHeaderID) { debug("Vorbis::Properties::read() -- invalid Vorbis identification header"); return; } pos += 7; d->vorbisVersion = data.toUInt(pos, false); pos += 4; d->channels = uchar(data[pos]); pos += 1; d->sampleRate = data.toUInt(pos, false); pos += 4; d->bitrateMaximum = data.toUInt(pos, false); pos += 4; d->bitrateNominal = data.toUInt(pos, false); pos += 4; d->bitrateMinimum = data.toUInt(pos, 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 = (int)((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."); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/ogg/vorbis/vorbisproperties.h���������������������������������������������������0000664�0000000�0000000�00000007734�12225024651�0022112�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_VORBISPROPERTIES_H #define TAGLIB_VORBISPROPERTIES_H #include "taglib_export.h" #include "audioproperties.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 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 TAGLIB_EXPORT 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 ������������������������������������taglib-1.9.1/taglib/ogg/xiphcomment.cpp�������������������������������������������������������������0000664�0000000�0000000�00000024675�12225024651�0020056�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tdebug.h> #include <xiphcomment.h> #include <tpropertymap.h> using namespace TagLib; class Ogg::XiphComment::XiphCommentPrivate { public: FieldListMap fieldListMap; String vendorID; String commentField; }; //////////////////////////////////////////////////////////////////////////////// // 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()) { d->commentField = "DESCRIPTION"; return d->fieldListMap["DESCRIPTION"].front(); } if(!d->fieldListMap["COMMENT"].isEmpty()) { d->commentField = "COMMENT"; return d->fieldListMap["COMMENT"].front(); } return String::null; } 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 d->fieldListMap["DATE"].front().toInt(); if(!d->fieldListMap["YEAR"].isEmpty()) return d->fieldListMap["YEAR"].front().toInt(); return 0; } TagLib::uint Ogg::XiphComment::track() const { if(!d->fieldListMap["TRACKNUMBER"].isEmpty()) return d->fieldListMap["TRACKNUMBER"].front().toInt(); if(!d->fieldListMap["TRACKNUM"].isEmpty()) return d->fieldListMap["TRACKNUM"].front().toInt(); return 0; } 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(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s); } void Ogg::XiphComment::setGenre(const String &s) { addField("GENRE", s); } void Ogg::XiphComment::setYear(uint i) { removeField("YEAR"); if(i == 0) removeField("DATE"); else addField("DATE", String::number(i)); } void Ogg::XiphComment::setTrack(uint i) { removeField("TRACKNUM"); 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; } PropertyMap Ogg::XiphComment::properties() const { return d->fieldListMap; } PropertyMap Ogg::XiphComment::setProperties(const PropertyMap &properties) { // check which keys are to be deleted StringList toRemove; for(FieldListMap::ConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) if (!properties.contains(it->first)) toRemove.append(it->first); for(StringList::ConstIterator it = toRemove.begin(); it != toRemove.end(); ++it) removeField(*it); // now go through keys in \a properties and check that the values match those in the xiph comment PropertyMap invalid; PropertyMap::ConstIterator it = properties.begin(); for(; it != properties.end(); ++it) { if(!checkKey(it->first)) invalid.insert(it->first, it->second); else if(!d->fieldListMap.contains(it->first) || !(it->second == d->fieldListMap[it->first])) { const StringList &sl = it->second; if(sl.size() == 0) // zero size string list -> remove the tag with all values removeField(it->first); else { // replace all strings in the list for the tag StringList::ConstIterator valueIterator = sl.begin(); addField(it->first, *valueIterator, true); ++valueIterator; for(; valueIterator != sl.end(); ++valueIterator) addField(it->first, *valueIterator, false); } } } return invalid; } bool Ogg::XiphComment::checkKey(const String &key) { if(key.size() < 1) return false; for(String::ConstIterator it = key.begin(); it != key.end(); it++) // forbid non-printable, non-ascii, '=' (#61) and '~' (#126) if (*it < 32 || *it >= 128 || *it == 61 || *it == 126) return false; return true; } 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() && !value.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(); while(it != d->fieldListMap[key].end()) { if(value == *it) it = d->fieldListMap[key].erase(it); else it++; } } else d->fieldListMap.erase(key); } bool Ogg::XiphComment::contains(const String &key) const { return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty(); } 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 // length of the data(String::UTF8) rather than the length 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<String, StringList> 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. uint pos = 0; const uint vendorLength = data.toUInt(0, false); pos += 4; d->vendorID = String(data.mid(pos, vendorLength), String::UTF8); pos += vendorLength; // Next the number of fields in the comment vector. const uint commentFields = data.toUInt(pos, false); pos += 4; if(commentFields > (data.size() - 8) / 4) { return; } for(uint 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. const uint commentLength = data.toUInt(pos, false); pos += 4; String comment = String(data.mid(pos, commentLength), String::UTF8); pos += commentLength; if(pos > data.size()) { break; } int commentSeparatorPosition = comment.find("="); if(commentSeparatorPosition == -1) { break; } String key = comment.substr(0, commentSeparatorPosition); String value = comment.substr(commentSeparatorPosition + 1); addField(key, value, false); } } �������������������������������������������������������������������taglib-1.9.1/taglib/ogg/xiphcomment.h���������������������������������������������������������������0000664�0000000�0000000�00000020062�12225024651�0017505�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_VORBISCOMMENT_H #define TAGLIB_VORBISCOMMENT_H #include "tag.h" #include "tlist.h" #include "tmap.h" #include "tstring.h" #include "tstringlist.h" #include "tbytevector.h" #include "taglib_export.h" 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<String, StringList> 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 TAGLIB_EXPORT 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: * * <ul> * <li>TITLE</li> * <li>VERSION</li> * <li>ALBUM</li> * <li>ARTIST</li> * <li>PERFORMER</li> * <li>COPYRIGHT</li> * <li>ORGANIZATION</li> * <li>DESCRIPTION</li> * <li>GENRE</li> * <li>DATE</li> * <li>LOCATION</li> * <li>CONTACT</li> * <li>ISRC</li> * </ul> * * 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; /*! * Implements the unified property interface -- export function. * The result is a one-to-one match of the Xiph comment, since it is * completely compatible with the property interface (in fact, a Xiph * comment is nothing more than a map from tag names to list of values, * as is the dict interface). */ PropertyMap properties() const; /*! * Implements the unified property interface -- import function. * The tags from the given map will be stored one-to-one in the file, * except for invalid keys (less than one character, non-ASCII, or * containing '=' or '~') in which case the according values will * be contained in the returned PropertyMap. */ PropertyMap setProperties(const PropertyMap&); /*! * Check if the given String is a valid Xiph comment key. */ static bool checkKey(const String&); /*! * 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); /*! * Returns true if the field is contained within the comment. * * \note This is safer than checking for membership in the FieldListMap. */ bool contains(const String &key) const; /*! * 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 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015153�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/aiff/����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0016060�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/aiff/aifffile.cpp����������������������������������������������������������0000664�0000000�0000000�00000010341�12225024651�0020330�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tdebug.h> #include <id3v2tag.h> #include <tstringlist.h> #include <tpropertymap.h> #include "aifffile.h" using namespace TagLib; class RIFF::AIFF::File::FilePrivate { public: FilePrivate() : properties(0), tag(0), tagChunkID("ID3 ") { } ~FilePrivate() { delete properties; delete tag; } Properties *properties; ID3v2::Tag *tag; ByteVector tagChunkID; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// RIFF::AIFF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : RIFF::File(file, BigEndian) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } RIFF::AIFF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : RIFF::File(stream, BigEndian) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } RIFF::AIFF::File::~File() { delete d; } ID3v2::Tag *RIFF::AIFF::File::tag() const { return d->tag; } PropertyMap RIFF::AIFF::File::properties() const { return d->tag->properties(); } void RIFF::AIFF::File::removeUnsupportedProperties(const StringList &unsupported) { d->tag->removeUnsupportedProperties(unsupported); } PropertyMap RIFF::AIFF::File::setProperties(const PropertyMap &properties) { return d->tag->setProperties(properties); } RIFF::AIFF::Properties *RIFF::AIFF::File::audioProperties() const { return d->properties; } bool RIFF::AIFF::File::save() { if(readOnly()) { debug("RIFF::AIFF::File::save() -- File is read only."); return false; } if(!isValid()) { debug("RIFF::AIFF::File::save() -- Trying to save invalid file."); return false; } setChunkData(d->tagChunkID, d->tag->render()); return true; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void RIFF::AIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { for(uint i = 0; i < chunkCount(); i++) { if(chunkName(i) == "ID3 " || chunkName(i) == "id3 ") { d->tagChunkID = chunkName(i); d->tag = new ID3v2::Tag(this, chunkOffset(i)); } else if(chunkName(i) == "COMM" && readProperties) d->properties = new Properties(chunkData(i), propertiesStyle); } if(!d->tag) d->tag = new ID3v2::Tag; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/aiff/aifffile.h������������������������������������������������������������0000664�0000000�0000000�00000012120�12225024651�0017772�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_AIFFFILE_H #define TAGLIB_AIFFFILE_H #include "rifffile.h" #include "id3v2tag.h" #include "aiffproperties.h" namespace TagLib { namespace RIFF { //! An implementation of AIFF metadata /*! * This is implementation of AIFF metadata. * * This supports an ID3v2 tag as well as reading stream from the ID3 RIFF * chunk as well as properties from the file. */ namespace AIFF { //! An implementation of TagLib::File with AIFF specific methods /*! * This implements and provides an interface for AIFF 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 AIFF files. */ class TAGLIB_EXPORT File : public TagLib::RIFF::File { public: /*! * Constructs an AIFF file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an AIFF file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); /*! * Returns the Tag for this file. * * \note This always returns a valid pointer regardless of whether or not * the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file * on disk actually has an ID3v2 tag. * * \see hasID3v2Tag() */ virtual ID3v2::Tag *tag() const; /*! * Implements the unified property interface -- export function. * This method forwards to ID3v2::Tag::properties(). */ PropertyMap properties() const; void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. * This method forwards to ID3v2::Tag::setProperties(). */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the AIFF::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 whether or not the file on disk actually has an ID3v2 tag. * * \see ID3v2Tag() */ bool hasID3v2Tag() const; private: File(const File &); File &operator=(const File &); void read(bool readProperties, Properties::ReadStyle propertiesStyle); class FilePrivate; FilePrivate *d; }; } } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/aiff/aiffproperties.cpp����������������������������������������������������0000664�0000000�0000000�00000011672�12225024651�0021615�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include <cmath> // ldexp is a c99 function, which might not be defined in <cmath> // so we pull in math.h too and hope it does the right (wrong) thing // wrt. c99 functions in C++ #include <math.h> #include "aiffproperties.h" //////////////////////////////////////////////////////////////////////////////// // nasty 80-bit float helpers //////////////////////////////////////////////////////////////////////////////// #define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) static double ConvertFromIeeeExtended(const TagLib::uchar *bytes) { double f; int expon; unsigned long hiMant, loMant; expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | ((unsigned long)(bytes[3] & 0xFF) << 16) | ((unsigned long)(bytes[4] & 0xFF) << 8) | ((unsigned long)(bytes[5] & 0xFF)); loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | ((unsigned long)(bytes[7] & 0xFF) << 16) | ((unsigned long)(bytes[8] & 0xFF) << 8) | ((unsigned long)(bytes[9] & 0xFF)); if (expon == 0 && hiMant == 0 && loMant == 0) f = 0; else { if(expon == 0x7FFF) /* Infinity or NaN */ f = HUGE_VAL; else { expon -= 16383; f = ldexp(UnsignedToFloat(hiMant), expon -= 31); f += ldexp(UnsignedToFloat(loMant), expon -= 32); } } if(bytes[0] & 0x80) return -f; else return f; } using namespace TagLib; class RIFF::AIFF::Properties::PropertiesPrivate { public: PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), sampleWidth(0), sampleFrames(0) { } int length; int bitrate; int sampleRate; int channels; int sampleWidth; uint sampleFrames; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// RIFF::AIFF::Properties::Properties(const ByteVector &data, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate; read(data); } RIFF::AIFF::Properties::~Properties() { delete d; } int RIFF::AIFF::Properties::length() const { return d->length; } int RIFF::AIFF::Properties::bitrate() const { return d->bitrate; } int RIFF::AIFF::Properties::sampleRate() const { return d->sampleRate; } int RIFF::AIFF::Properties::channels() const { return d->channels; } int RIFF::AIFF::Properties::sampleWidth() const { return d->sampleWidth; } TagLib::uint RIFF::AIFF::Properties::sampleFrames() const { return d->sampleFrames; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void RIFF::AIFF::Properties::read(const ByteVector &data) { d->channels = data.toShort(0U); d->sampleFrames = data.toUInt(2U); d->sampleWidth = data.toShort(6U); double sampleRate = ConvertFromIeeeExtended(reinterpret_cast<const uchar *>(data.data() + 8)); d->sampleRate = (int)sampleRate; d->bitrate = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0); d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; } ����������������������������������������������������������������������taglib-1.9.1/taglib/riff/aiff/aiffproperties.h������������������������������������������������������0000664�0000000�0000000�00000005607�12225024651�0021263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_AIFFPROPERTIES_H #define TAGLIB_AIFFPROPERTIES_H #include "audioproperties.h" namespace TagLib { namespace RIFF { namespace AIFF { class File; //! An implementation of audio property reading for AIFF /*! * This reads the data from an AIFF stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of AIFF::Properties with the data read from the * ByteVector \a data. */ Properties(const ByteVector &data, ReadStyle style); /*! * Destroys this AIFF::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; int sampleWidth() const; uint sampleFrames() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(const ByteVector &data); class PropertiesPrivate; PropertiesPrivate *d; }; } } } #endif �������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/rifffile.cpp���������������������������������������������������������������0000664�0000000�0000000�00000020540�12225024651�0017446�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tdebug.h> #include <tstring.h> #include "rifffile.h" #include <algorithm> #include <vector> using namespace TagLib; struct Chunk { ByteVector name; TagLib::uint offset; TagLib::uint size; char padding; }; class RIFF::File::FilePrivate { public: FilePrivate() : endianness(BigEndian), size(0) { } Endianness endianness; ByteVector type; TagLib::uint size; ByteVector format; std::vector<Chunk> chunks; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// RIFF::File::~File() { delete d; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// RIFF::File::File(FileName file, Endianness endianness) : TagLib::File(file) { d = new FilePrivate; d->endianness = endianness; if(isOpen()) read(); } RIFF::File::File(IOStream *stream, Endianness endianness) : TagLib::File(stream) { d = new FilePrivate; d->endianness = endianness; if(isOpen()) read(); } TagLib::uint RIFF::File::riffSize() const { return d->size; } TagLib::uint RIFF::File::chunkCount() const { return d->chunks.size(); } TagLib::uint RIFF::File::chunkDataSize(uint i) const { return d->chunks[i].size; } TagLib::uint RIFF::File::chunkOffset(uint i) const { return d->chunks[i].offset; } TagLib::uint RIFF::File::chunkPadding(uint i) const { return d->chunks[i].padding; } ByteVector RIFF::File::chunkName(uint i) const { if(i >= chunkCount()) return ByteVector::null; return d->chunks[i].name; } ByteVector RIFF::File::chunkData(uint i) { if(i >= chunkCount()) return ByteVector::null; // Offset for the first subchunk's data long begin = 12 + 8; for(uint it = 0; it < i; it++) begin += 8 + d->chunks[it].size + d->chunks[it].padding; seek(begin); return readBlock(d->chunks[i].size); } void RIFF::File::setChunkData(uint i, const ByteVector &data) { // First we update the global size d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding); insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4); // Now update the specific chunk writeChunk(chunkName(i), data, d->chunks[i].offset - 8, d->chunks[i].size + d->chunks[i].padding + 8); d->chunks[i].size = data.size(); d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0; // Now update the internal offsets for(i++; i < d->chunks.size(); i++) d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding; } void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data) { setChunkData(name, data, false); } void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate) { if(d->chunks.size() == 0) { debug("RIFF::File::setChunkData - No valid chunks found."); return; } if(alwaysCreate && name != "LIST") { debug("RIFF::File::setChunkData - alwaysCreate should be used for only \"LIST\" chunks."); return; } if(!alwaysCreate) { for(uint i = 0; i < d->chunks.size(); i++) { if(d->chunks[i].name == name) { setChunkData(i, data); return; } } } // Couldn't find an existing chunk, so let's create a new one. uint i = d->chunks.size() - 1; ulong offset = d->chunks[i].offset + d->chunks[i].size; // First we update the global size d->size += (offset & 1) + data.size() + 8; insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4); // Now add the chunk to the file writeChunk(name, data, offset, std::max<long>(0, length() - offset), (offset & 1) ? 1 : 0); // And update our internal structure if (offset & 1) { d->chunks[i].padding = 1; offset++; } Chunk chunk; chunk.name = name; chunk.size = data.size(); chunk.offset = offset + 8; chunk.padding = (data.size() & 0x01) ? 1 : 0; d->chunks.push_back(chunk); } void RIFF::File::removeChunk(uint i) { if(i >= d->chunks.size()) return; removeBlock(d->chunks[i].offset - 8, d->chunks[i].size + 8); d->chunks.erase(d->chunks.begin() + i); } void RIFF::File::removeChunk(const ByteVector &name) { std::vector<Chunk> newChunks; for(size_t i = 0; i < d->chunks.size(); ++i) { if(d->chunks[i].name == name) removeBlock(d->chunks[i].offset - 8, d->chunks[i].size + 8); else newChunks.push_back(d->chunks[i]); } d->chunks.swap(newChunks); } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// static bool isValidChunkID(const ByteVector &name) { if(name.size() != 4) { return false; } for(int i = 0; i < 4; i++) { if(name[i] < 32 || name[i] > 127) { return false; } } return true; } void RIFF::File::read() { bool bigEndian = (d->endianness == BigEndian); d->type = readBlock(4); d->size = readBlock(4).toUInt(bigEndian); d->format = readBlock(4); // + 8: chunk header at least, fix for additional junk bytes while(tell() + 8 <= length()) { ByteVector chunkName = readBlock(4); uint chunkSize = readBlock(4).toUInt(bigEndian); if(!isValidChunkID(chunkName)) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID"); setValid(false); break; } if(static_cast<ulonglong>(tell()) + chunkSize > static_cast<ulonglong>(length())) { debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)"); setValid(false); break; } Chunk chunk; chunk.name = chunkName; chunk.size = chunkSize; chunk.offset = tell(); seek(chunk.size, Current); // check padding chunk.padding = 0; long uPosNotPadded = tell(); if((uPosNotPadded & 0x01) != 0) { ByteVector iByte = readBlock(1); if((iByte.size() != 1) || (iByte[0] != 0)) { // not well formed, re-seek seek(uPosNotPadded, Beginning); } else { chunk.padding = 1; } } d->chunks.push_back(chunk); } } void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, ulong offset, ulong replace, uint leadingPadding) { ByteVector combined; if(leadingPadding) { combined.append(ByteVector(leadingPadding, '\x00')); } combined.append(name); combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian)); combined.append(data); if((data.size() & 0x01) != 0) { combined.append('\x00'); } insert(combined, offset, replace); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/rifffile.h�����������������������������������������������������������������0000664�0000000�0000000�00000012324�12225024651�0017114�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_RIFFFILE_H #define TAGLIB_RIFFFILE_H #include "taglib_export.h" #include "tfile.h" namespace TagLib { //! An implementation of TagLib::File with RIFF specific methods namespace RIFF { //! An RIFF file class with some useful methods specific to RIFF /*! * This implements the generic TagLib::File API and additionally provides * access to properties that are distinct to RIFF files, notably access * to the different ID3 tags. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * Destroys this instance of the File. */ virtual ~File(); protected: enum Endianness { BigEndian, LittleEndian }; File(FileName file, Endianness endianness); File(IOStream *stream, Endianness endianness); /*! * \return The size of the main RIFF chunk. */ uint riffSize() const; /*! * \return The number of chunks in the file. */ uint chunkCount() const; /*! * \return The offset within the file for the selected chunk number. */ uint chunkOffset(uint i) const; /*! * \return The size of the chunk data. */ uint chunkDataSize(uint i) const; /*! * \return The size of the padding after the chunk (can be either 0 or 1). */ uint chunkPadding(uint i) const; /*! * \return The name of the specified chunk, for instance, "COMM" or "ID3 " */ ByteVector chunkName(uint i) const; /*! * Reads the chunk data from the file and returns it. * * \note This \e will move the read pointer for the file. */ ByteVector chunkData(uint i); /*! * Sets the data for the the specified chunk to \a data. * * \warning This will update the file immediately. */ void setChunkData(uint i, const ByteVector &data); /*! * Sets the data for the chunk \a name to \a data. If a chunk with the * given name already exists it will be overwritten, otherwise it will be * created after the existing chunks. * * \warning This will update the file immediately. */ void setChunkData(const ByteVector &name, const ByteVector &data); /*! * Sets the data for the chunk \a name to \a data. If a chunk with the * given name already exists it will be overwritten, otherwise it will be * created after the existing chunks. * * \note If \a alwaysCreate is true, a new chunk is created regardless of * whether or not the chunk \a name exists. It should only be used for * "LIST" chunks. * * \warning This will update the file immediately. */ void setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate); /*! * Removes the specified chunk. * * \warning This will update the file immediately. */ void removeChunk(uint i); /*! * Removes the chunk \a name. * * \warning This will update the file immediately. * \warning This removes all the chunks with the given name. */ void removeChunk(const ByteVector &name); private: File(const File &); File &operator=(const File &); void read(); void writeChunk(const ByteVector &name, const ByteVector &data, ulong offset, ulong replace = 0, uint leadingPadding = 0); class FilePrivate; FilePrivate *d; }; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/wav/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015750�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/wav/infotag.cpp������������������������������������������������������������0000664�0000000�0000000�00000014365�12225024651�0020114�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Tsuda Kageyu 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tdebug.h> #include <tfile.h> #include "infotag.h" using namespace TagLib; using namespace RIFF::Info; namespace { static bool isValidChunkID(const ByteVector &name) { if(name.size() != 4) return false; for(int i = 0; i < 4; i++) { if(name[i] < 32 || name[i] > 127) return false; } return true; } } class RIFF::Info::Tag::TagPrivate { public: TagPrivate() {} FieldListMap fieldListMap; static const StringHandler *stringHandler; }; //////////////////////////////////////////////////////////////////////////////// // StringHandler implementation //////////////////////////////////////////////////////////////////////////////// StringHandler::StringHandler() { } StringHandler::~StringHandler() { } String RIFF::Info::StringHandler::parse(const ByteVector &data) const { return String(data, String::UTF8); } ByteVector RIFF::Info::StringHandler::render(const String &s) const { return s.data(String::UTF8); } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// static const StringHandler defaultStringHandler; const RIFF::Info::StringHandler *RIFF::Info::Tag::TagPrivate::stringHandler = &defaultStringHandler; RIFF::Info::Tag::Tag(const ByteVector &data) : TagLib::Tag() , d(new TagPrivate()) { parse(data); } RIFF::Info::Tag::Tag() : TagLib::Tag() , d(new TagPrivate()) { } RIFF::Info::Tag::~Tag() { delete d; } String RIFF::Info::Tag::title() const { return fieldText("INAM"); } String RIFF::Info::Tag::artist() const { return fieldText("IART"); } String RIFF::Info::Tag::album() const { return fieldText("IPRD"); } String RIFF::Info::Tag::comment() const { return fieldText("ICMT"); } String RIFF::Info::Tag::genre() const { return fieldText("IGNR"); } TagLib::uint RIFF::Info::Tag::year() const { return fieldText("ICRD").substr(0, 4).toInt(); } TagLib::uint RIFF::Info::Tag::track() const { return fieldText("IPRT").toInt(); } void RIFF::Info::Tag::setTitle(const String &s) { setFieldText("INAM", s); } void RIFF::Info::Tag::setArtist(const String &s) { setFieldText("IART", s); } void RIFF::Info::Tag::setAlbum(const String &s) { setFieldText("IPRD", s); } void RIFF::Info::Tag::setComment(const String &s) { setFieldText("ICMT", s); } void RIFF::Info::Tag::setGenre(const String &s) { setFieldText("IGNR", s); } void RIFF::Info::Tag::setYear(uint i) { if(i != 0) setFieldText("ICRD", String::number(i)); else d->fieldListMap.erase("ICRD"); } void RIFF::Info::Tag::setTrack(uint i) { if(i != 0) setFieldText("IPRT", String::number(i)); else d->fieldListMap.erase("IPRT"); } bool RIFF::Info::Tag::isEmpty() const { return d->fieldListMap.isEmpty(); } FieldListMap RIFF::Info::Tag::fieldListMap() const { return d->fieldListMap; } String RIFF::Info::Tag::fieldText(const ByteVector &id) const { if(d->fieldListMap.contains(id)) return String(d->fieldListMap[id]); else return String(); } void RIFF::Info::Tag::setFieldText(const ByteVector &id, const String &s) { // id must be four-byte long pure ascii string. if(!isValidChunkID(id)) return; if(!s.isEmpty()) d->fieldListMap[id] = s; else removeField(id); } void RIFF::Info::Tag::removeField(const ByteVector &id) { if(d->fieldListMap.contains(id)) d->fieldListMap.erase(id); } ByteVector RIFF::Info::Tag::render() const { ByteVector data("INFO"); FieldListMap::ConstIterator it = d->fieldListMap.begin(); for(; it != d->fieldListMap.end(); ++it) { ByteVector text = TagPrivate::stringHandler->render(it->second); if(text.isEmpty()) continue; data.append(it->first); data.append(ByteVector::fromUInt(text.size() + 1, false)); data.append(text); do { data.append('\0'); } while(data.size() & 1); } if(data.size() == 4) return ByteVector(); else return data; } void RIFF::Info::Tag::setStringHandler(const StringHandler *handler) { if(handler) TagPrivate::stringHandler = handler; else TagPrivate::stringHandler = &defaultStringHandler; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void RIFF::Info::Tag::parse(const ByteVector &data) { uint p = 4; while(p < data.size()) { const uint size = data.toUInt(p + 4, false); d->fieldListMap[data.mid(p, 4)] = TagPrivate::stringHandler->parse(data.mid(p + 8, size)); p += ((size + 1) & ~1) + 8; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/wav/infotag.h��������������������������������������������������������������0000664�0000000�0000000�00000014673�12225024651�0017563�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Tsuda Kageyu email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_INFOTAG_H #define TAGLIB_INFOTAG_H #include "tag.h" #include "tmap.h" #include "tstring.h" #include "tstringlist.h" #include "tbytevector.h" #include "taglib_export.h" namespace TagLib { class File; //! A RIFF Info tag implementation. namespace RIFF { namespace Info { typedef Map<ByteVector, String> FieldListMap; //! A abstraction for the string to data encoding in Info tags. /*! * RIFF Info tag has no clear definitions about character encodings. * In practice, local encoding of each system is largely used and UTF-8 is * popular too. * * Here is an option to read and write tags in your preferrd encoding * by subclassing this class, reimplementing parse() and render() and setting * your reimplementation as the default with Info::Tag::setStringHandler(). * * \see ID3v1::Tag::setStringHandler() */ class TAGLIB_EXPORT StringHandler { public: StringHandler(); ~StringHandler(); /*! * Decode a string from \a data. The default implementation assumes that * \a data is an UTF-8 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 UTF-8 string. */ virtual ByteVector render(const String &s) const; }; //! The main class in the ID3v2 implementation /*! * This is the main class in the INFO tag implementation. RIFF INFO tag is a * metadata format found in WAV audio and AVI video files. Though it is a part * of Microsoft/IBM's RIFF specification, the author could not find the official * documents about it. So, this implementation is referring to unofficial documents * online and some applications' behaviors especially Windows Explorer. */ class TAGLIB_EXPORT Tag : public TagLib::Tag { public: /*! * Constructs an empty Info tag. */ Tag(); /*! * Constructs an Info tag read from \a data which is contents of "LIST" chunk. */ Tag(const ByteVector &data); 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 copy of the internal fields of the tag. The returned map directly * reflects the contents of the "INFO" chunk. * * \note Modifying this map does not affect the tag's internal data. * Use setFieldText() and removeField() instead. * * \see setFieldText() * \see removeField() */ FieldListMap fieldListMap() const; /* * Gets the value of the field with the ID \a id. */ String fieldText(const ByteVector &id) const; /* * Sets the value of the field with the ID \a id to \a s. * If the field does not exist, it is created. * If \s is empty, the field is removed. * * \note fieldId must be four-byte long pure ASCII string. This function * performs nothing if fieldId is invalid. */ void setFieldText(const ByteVector &id, const String &s); /* * Removes the field with the ID \a id. */ void removeField(const ByteVector &id); /*! * Render the tag back to binary data, suitable to be written to disk. * * \note Returns empty ByteVector is the tag contains no fields. */ ByteVector render() const; /*! * Sets the string handler that decides how the text data will be * converted to and from binary data. * If the parameter \a handler is null, the previous handler is * released and default UTF-8 handler is restored. * * \note The caller is responsible for deleting the previous handler * as needed after it is released. * * \see StringHandler */ static void setStringHandler(const StringHandler *handler); protected: /*! * 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 ���������������������������������������������������������������������taglib-1.9.1/taglib/riff/wav/wavfile.cpp������������������������������������������������������������0000664�0000000�0000000�00000014651�12225024651�0020120�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tbytevector.h" #include "tdebug.h" #include "tstringlist.h" #include "tpropertymap.h" #include "wavfile.h" #include "id3v2tag.h" #include "infotag.h" #include "tagunion.h" using namespace TagLib; namespace { enum { ID3v2Index = 0, InfoIndex = 1 }; } class RIFF::WAV::File::FilePrivate { public: FilePrivate() : properties(0), tagChunkID("ID3 "), hasID3v2(false), hasInfo(false) { } ~FilePrivate() { delete properties; } Properties *properties; ByteVector tagChunkID; TagUnion tag; bool hasID3v2; bool hasInfo; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// RIFF::WAV::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : RIFF::File(file, LittleEndian) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } RIFF::WAV::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : RIFF::File(stream, LittleEndian) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } RIFF::WAV::File::~File() { delete d; } ID3v2::Tag *RIFF::WAV::File::tag() const { return ID3v2Tag(); } ID3v2::Tag *RIFF::WAV::File::ID3v2Tag() const { return d->tag.access<ID3v2::Tag>(ID3v2Index, false); } RIFF::Info::Tag *RIFF::WAV::File::InfoTag() const { return d->tag.access<RIFF::Info::Tag>(InfoIndex, false); } PropertyMap RIFF::WAV::File::properties() const { return tag()->properties(); } void RIFF::WAV::File::removeUnsupportedProperties(const StringList &unsupported) { tag()->removeUnsupportedProperties(unsupported); } PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties) { return tag()->setProperties(properties); } RIFF::WAV::Properties *RIFF::WAV::File::audioProperties() const { return d->properties; } bool RIFF::WAV::File::save() { return RIFF::WAV::File::save(AllTags); } bool RIFF::WAV::File::save(TagTypes tags, bool stripOthers, int id3v2Version) { if(readOnly()) { debug("RIFF::WAV::File::save() -- File is read only."); return false; } if(!isValid()) { debug("RIFF::WAV::File::save() -- Trying to save invalid file."); return false; } if(stripOthers) strip(static_cast<TagTypes>(AllTags & ~tags)); ID3v2::Tag *id3v2tag = d->tag.access<ID3v2::Tag>(ID3v2Index, false); if(!id3v2tag->isEmpty()) { if(tags & ID3v2) { setChunkData(d->tagChunkID, id3v2tag->render(id3v2Version)); d->hasID3v2 = true; } } Info::Tag *infotag = d->tag.access<Info::Tag>(InfoIndex, false); if(!infotag->isEmpty()) { if(tags & Info) { int chunkId = findInfoTagChunk(); if(chunkId != -1) setChunkData(chunkId, infotag->render()); else setChunkData("LIST", infotag->render(), true); d->hasInfo = true; } } return true; } bool RIFF::WAV::File::hasID3v2Tag() const { return d->hasID3v2; } bool RIFF::WAV::File::hasInfoTag() const { return d->hasInfo; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void RIFF::WAV::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { ByteVector formatData; uint streamLength = 0; for(uint i = 0; i < chunkCount(); i++) { String name = chunkName(i); if(name == "ID3 " || name == "id3 ") { d->tagChunkID = chunkName(i); d->tag.set(ID3v2Index, new ID3v2::Tag(this, chunkOffset(i))); d->hasID3v2 = true; } else if(name == "fmt " && readProperties) formatData = chunkData(i); else if(name == "data" && readProperties) streamLength = chunkDataSize(i); else if(name == "LIST") { ByteVector data = chunkData(i); ByteVector type = data.mid(0, 4); if(type == "INFO") { d->tag.set(InfoIndex, new RIFF::Info::Tag(data)); d->hasInfo = true; } } } if (!d->tag[ID3v2Index]) d->tag.set(ID3v2Index, new ID3v2::Tag); if (!d->tag[InfoIndex]) d->tag.set(InfoIndex, new RIFF::Info::Tag); if(!formatData.isEmpty()) d->properties = new Properties(formatData, streamLength, propertiesStyle); } void RIFF::WAV::File::strip(TagTypes tags) { if(tags & ID3v2) removeChunk(d->tagChunkID); if(tags & Info){ TagLib::uint chunkId = findInfoTagChunk(); if(chunkId != TagLib::uint(-1)) removeChunk(chunkId); } } TagLib::uint RIFF::WAV::File::findInfoTagChunk() { for(uint i = 0; i < chunkCount(); ++i) { if(chunkName(i) == "LIST" && chunkData(i).mid(0, 4) == "INFO") { return i; } } return TagLib::uint(-1); } ���������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/wav/wavfile.h��������������������������������������������������������������0000664�0000000�0000000�00000014715�12225024651�0017566�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_WAVFILE_H #define TAGLIB_WAVFILE_H #include "rifffile.h" #include "id3v2tag.h" #include "infotag.h" #include "wavproperties.h" namespace TagLib { namespace RIFF { //! An implementation of WAV metadata /*! * This is implementation of WAV metadata. * * This supports an ID3v2 tag as well as reading stream from the ID3 RIFF * chunk as well as properties from the file. */ namespace WAV { //! An implementation of TagLib::File with WAV specific methods /*! * This implements and provides an interface for WAV 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 WAV files. */ class TAGLIB_EXPORT File : public TagLib::RIFF::File { public: enum TagTypes { //! Empty set. Matches no tag types. NoTags = 0x0000, //! Matches ID3v2 tags. ID3v2 = 0x0001, //! Matches Info tags. Info = 0x0002, //! Matches all tag types. AllTags = 0xffff }; /*! * Constructs a WAV file from \a file. If \a readProperties is true the * file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs a WAV file from \a stream. If \a readProperties is true the * file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); /*! * Returns the ID3v2 Tag for this file. * * \note This method does not return all the tags for this file for * backward compatibility. Will be fixed in TagLib 2.0. */ ID3v2::Tag *tag() const; /*! * Returns the ID3v2 Tag for this file. * * \note This always returns a valid pointer regardless of whether or not * the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the * file on disk actually has an ID3v2 tag. * * \see hasID3v2Tag() */ ID3v2::Tag *ID3v2Tag() const; /*! * Returns the RIFF INFO Tag for this file. * * \note This always returns a valid pointer regardless of whether or not * the file on disk has a RIFF INFO tag. Use hasInfoTag() to check if the * file on disk actually has a RIFF INFO tag. * * \see hasInfoTag() */ Info::Tag *InfoTag() const; /*! * Implements the unified property interface -- export function. * This method forwards to ID3v2::Tag::properties(). */ PropertyMap properties() const; void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. * This method forwards to ID3v2::Tag::setProperties(). */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the WAV::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(); bool save(TagTypes tags, bool stripOthers = true, int id3v2Version = 4); /*! * Returns whether or not the file on disk actually has an ID3v2 tag. * * \see ID3v2Tag() */ bool hasID3v2Tag() const; /*! * Returns whether or not the file on disk actually has a RIFF INFO tag. * * \see InfoTag() */ bool hasInfoTag() const; private: File(const File &); File &operator=(const File &); void read(bool readProperties, Properties::ReadStyle propertiesStyle); void strip(TagTypes tags); /*! * Returns the index of the chunk that its name is "LIST" and list type is "INFO". */ uint findInfoTagChunk(); class FilePrivate; FilePrivate *d; }; } } } #endif ���������������������������������������������������taglib-1.9.1/taglib/riff/wav/wavproperties.cpp������������������������������������������������������0000664�0000000�0000000�00000007567�12225024651�0021405�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "wavproperties.h" #include <tstring.h> #include <tdebug.h> #include <cmath> #include <math.h> using namespace TagLib; class RIFF::WAV::Properties::PropertiesPrivate { public: PropertiesPrivate(uint streamLength = 0) : format(0), length(0), bitrate(0), sampleRate(0), channels(0), sampleWidth(0), sampleFrames(0), streamLength(streamLength) { } short format; int length; int bitrate; int sampleRate; int channels; int sampleWidth; uint sampleFrames; uint streamLength; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// RIFF::WAV::Properties::Properties(const ByteVector &data, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(); read(data); } RIFF::WAV::Properties::Properties(const ByteVector &data, uint streamLength, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(streamLength); read(data); } RIFF::WAV::Properties::~Properties() { delete d; } int RIFF::WAV::Properties::length() const { return d->length; } int RIFF::WAV::Properties::bitrate() const { return d->bitrate; } int RIFF::WAV::Properties::sampleRate() const { return d->sampleRate; } int RIFF::WAV::Properties::channels() const { return d->channels; } int RIFF::WAV::Properties::sampleWidth() const { return d->sampleWidth; } TagLib::uint RIFF::WAV::Properties::sampleFrames() const { return d->sampleFrames; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void RIFF::WAV::Properties::read(const ByteVector &data) { d->format = data.toShort(0, false); d->channels = data.toShort(2, false); d->sampleRate = data.toUInt(4, false); d->sampleWidth = data.toShort(14, false); const uint byteRate = data.toUInt(8, false); d->bitrate = byteRate * 8 / 1000; d->length = byteRate > 0 ? d->streamLength / byteRate : 0; if(d->channels > 0 && d->sampleWidth > 0) d->sampleFrames = d->streamLength / (d->channels * ((d->sampleWidth + 7) / 8)); } �����������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/riff/wav/wavproperties.h��������������������������������������������������������0000664�0000000�0000000�00000006256�12225024651�0021044�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_WAVPROPERTIES_H #define TAGLIB_WAVPROPERTIES_H #include "taglib.h" #include "audioproperties.h" namespace TagLib { class ByteVector; namespace RIFF { namespace WAV { class File; //! An implementation of audio property reading for WAV /*! * This reads the data from an WAV stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of WAV::Properties with the data read from the * ByteVector \a data. */ Properties(const ByteVector &data, ReadStyle style); /*! * Create an instance of WAV::Properties with the data read from the * ByteVector \a data and the length calculated using \a streamLength. */ Properties(const ByteVector &data, uint streamLength, ReadStyle style); /*! * Destroys this WAV::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; int sampleWidth() const; uint sampleFrames() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(const ByteVector &data); class PropertiesPrivate; PropertiesPrivate *d; }; } } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/s3m/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014727�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/s3m/s3mfile.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000014622�12225024651�0017002�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "s3mfile.h" #include "tstringlist.h" #include "tdebug.h" #include "modfileprivate.h" #include "tpropertymap.h" #include <iostream> using namespace TagLib; using namespace S3M; class S3M::File::FilePrivate { public: FilePrivate(AudioProperties::ReadStyle propertiesStyle) : properties(propertiesStyle) { } Mod::Tag tag; S3M::Properties properties; }; S3M::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } S3M::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } S3M::File::~File() { delete d; } Mod::Tag *S3M::File::tag() const { return &d->tag; } PropertyMap S3M::File::properties() const { return d->tag.properties(); } PropertyMap S3M::File::setProperties(const PropertyMap &properties) { return d->tag.setProperties(properties); } S3M::Properties *S3M::File::audioProperties() const { return &d->properties; } bool S3M::File::save() { if(readOnly()) { debug("S3M::File::save() - Cannot save to a read only file."); return false; } // note: if title starts with "Extended Module: " // the file would look like an .xm file seek(0); writeString(d->tag.title(), 27); // string terminating NUL is not optional: writeByte(0); seek(32); ushort length = 0; ushort sampleCount = 0; if(!readU16L(length) || !readU16L(sampleCount)) return false; seek(28, Current); int channels = 0; for(int i = 0; i < 32; ++ i) { uchar setting = 0; if(!readByte(setting)) return false; // or if(setting >= 128)? // or channels = i + 1;? // need a better spec! if(setting != 0xff) ++ channels; } seek(channels, Current); StringList lines = d->tag.comment().split("\n"); // write comment as sample names: for(ushort i = 0; i < sampleCount; ++ i) { seek(96L + length + ((long)i << 1)); ushort instrumentOffset = 0; if(!readU16L(instrumentOffset)) return false; seek(((long)instrumentOffset << 4) + 48); if(i < lines.size()) writeString(lines[i], 27); else writeString(String::null, 27); // string terminating NUL is not optional: writeByte(0); } return true; } void S3M::File::read(bool) { if(!isOpen()) return; READ_STRING(d->tag.setTitle, 28); READ_BYTE_AS(mark); READ_BYTE_AS(type); READ_ASSERT(mark == 0x1A && type == 0x10); seek(32); READ_U16L_AS(length); READ_U16L_AS(sampleCount); d->properties.setSampleCount(sampleCount); READ_U16L(d->properties.setPatternCount); READ_U16L(d->properties.setFlags); READ_U16L(d->properties.setTrackerVersion); READ_U16L(d->properties.setFileFormatVersion); READ_ASSERT(readBlock(4) == "SCRM"); READ_BYTE(d->properties.setGlobalVolume); READ_BYTE(d->properties.setBpmSpeed); READ_BYTE(d->properties.setTempo); READ_BYTE_AS(masterVolume); d->properties.setMasterVolume(masterVolume & 0x7f); d->properties.setStereo((masterVolume & 0x80) != 0); // I've seen players who call the next two bytes // "ultra click" and "use panning values" (if == 0xFC). // I don't see them in any spec, though. // Hm, but there is "UltraClick-removal" and some other // variables in ScreamTracker IIIs GUI. seek(12, Current); int channels = 0; for(int i = 0; i < 32; ++ i) { READ_BYTE_AS(setting); // or if(setting >= 128)? // or channels = i + 1;? // need a better spec! if(setting != 0xff) ++ channels; } d->properties.setChannels(channels); seek(96); ushort realLength = 0; for(ushort i = 0; i < length; ++ i) { READ_BYTE_AS(order); if(order == 255) break; if(order != 254) ++ realLength; } d->properties.setLengthInPatterns(realLength); seek(channels, Current); // Note: The S3M spec mentions samples and instruments, but in // the header there are only pointers to instruments. // However, there I never found instruments (SCRI) but // instead samples (SCRS). StringList comment; for(ushort i = 0; i < sampleCount; ++ i) { seek(96L + length + ((long)i << 1)); READ_U16L_AS(sampleHeaderOffset); seek((long)sampleHeaderOffset << 4); READ_BYTE_AS(sampleType); READ_STRING_AS(dosFileName, 13); READ_U16L_AS(sampleDataOffset); READ_U32L_AS(sampleLength); READ_U32L_AS(repeatStart); READ_U32L_AS(repeatStop); READ_BYTE_AS(sampleVolume); seek(1, Current); READ_BYTE_AS(packing); READ_BYTE_AS(sampleFlags); READ_U32L_AS(baseFrequency); seek(12, Current); READ_STRING_AS(sampleName, 28); // The next 4 bytes should be "SCRS", but I've found // files that are otherwise ok with 4 nils instead. // READ_ASSERT(readBlock(4) == "SCRS"); comment.append(sampleName); } d->tag.setComment(comment.toString("\n")); d->tag.setTrackerName("ScreamTracker III"); } ��������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/s3m/s3mfile.h�������������������������������������������������������������������0000664�0000000�0000000�00000007412�12225024651�0016446�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_S3MFILE_H #define TAGLIB_S3MFILE_H #include "tfile.h" #include "audioproperties.h" #include "taglib_export.h" #include "modfilebase.h" #include "modtag.h" #include "s3mproperties.h" namespace TagLib { namespace S3M { class TAGLIB_EXPORT File : public Mod::FileBase { public: /*! * Constructs a ScreamTracker III from \a file. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. */ File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Constructs a ScreamTracker III file from \a stream. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. */ File(IOStream *stream, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); Mod::Tag *tag() const; /*! * Implements the unified property interface -- export function. * Forwards to Mod::Tag::properties(). */ PropertyMap properties() const; /*! * Implements the unified property interface -- import function. * Forwards to Mod::Tag::setProperties(). */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the S3M::Properties for this file. If no audio properties * were read then this will return a null pointer. */ S3M::Properties *audioProperties() const; /*! * Save the file. * This is the same as calling save(AllTags); * * \note Saving ScreamTracker III tags is not supported. */ bool save(); private: File(const File &); File &operator=(const File &); void read(bool readProperties); class FilePrivate; FilePrivate *d; }; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/s3m/s3mproperties.cpp�����������������������������������������������������������0000664�0000000�0000000�00000010537�12225024651�0020260�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "s3mproperties.h" using namespace TagLib; using namespace S3M; class S3M::Properties::PropertiesPrivate { public: PropertiesPrivate() : lengthInPatterns(0), channels(0), stereo(false), sampleCount(0), patternCount(0), flags(0), trackerVersion(0), fileFormatVersion(0), globalVolume(0), masterVolume(0), tempo(0), bpmSpeed(0) { } ushort lengthInPatterns; int channels; bool stereo; ushort sampleCount; ushort patternCount; ushort flags; ushort trackerVersion; ushort fileFormatVersion; uchar globalVolume; uchar masterVolume; uchar tempo; uchar bpmSpeed; }; S3M::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate) { } S3M::Properties::~Properties() { delete d; } int S3M::Properties::length() const { return 0; } int S3M::Properties::bitrate() const { return 0; } int S3M::Properties::sampleRate() const { return 0; } int S3M::Properties::channels() const { return d->channels; } TagLib::ushort S3M::Properties::lengthInPatterns() const { return d->lengthInPatterns; } bool S3M::Properties::stereo() const { return d->stereo; } TagLib::ushort S3M::Properties::sampleCount() const { return d->sampleCount; } TagLib::ushort S3M::Properties::patternCount() const { return d->patternCount; } TagLib::ushort S3M::Properties::flags() const { return d->flags; } TagLib::ushort S3M::Properties::trackerVersion() const { return d->trackerVersion; } TagLib::ushort S3M::Properties::fileFormatVersion() const { return d->fileFormatVersion; } uchar S3M::Properties::globalVolume() const { return d->globalVolume; } uchar S3M::Properties::masterVolume() const { return d->masterVolume; } uchar S3M::Properties::tempo() const { return d->tempo; } uchar S3M::Properties::bpmSpeed() const { return d->bpmSpeed; } void S3M::Properties::setLengthInPatterns(ushort lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } void S3M::Properties::setChannels(int channels) { d->channels = channels; } void S3M::Properties::setStereo(bool stereo) { d->stereo = stereo; } void S3M::Properties::setSampleCount(ushort sampleCount) { d->sampleCount = sampleCount; } void S3M::Properties::setPatternCount(ushort patternCount) { d->patternCount = patternCount; } void S3M::Properties::setFlags(ushort flags) { d->flags = flags; } void S3M::Properties::setTrackerVersion(ushort trackerVersion) { d->trackerVersion = trackerVersion; } void S3M::Properties::setFileFormatVersion(ushort fileFormatVersion) { d->fileFormatVersion = fileFormatVersion; } void S3M::Properties::setGlobalVolume(uchar globalVolume) { d->globalVolume = globalVolume; } void S3M::Properties::setMasterVolume(uchar masterVolume) { d->masterVolume = masterVolume; } void S3M::Properties::setTempo(uchar tempo) { d->tempo = tempo; } void S3M::Properties::setBpmSpeed(uchar bpmSpeed) { d->bpmSpeed = bpmSpeed; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/s3m/s3mproperties.h�������������������������������������������������������������0000664�0000000�0000000�00000006535�12225024651�0017730�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_S3MPROPERTIES_H #define TAGLIB_S3MPROPERTIES_H #include "taglib.h" #include "audioproperties.h" namespace TagLib { namespace S3M { class TAGLIB_EXPORT Properties : public AudioProperties { friend class File; public: /*! Flag bits. */ enum { ST2Vibrato = 1, ST2Tempo = 2, AmigaSlides = 4, Vol0MixOptimizations = 8, AmigaLimits = 16, EnableFilter = 32, CustomData = 128 }; Properties(AudioProperties::ReadStyle propertiesStyle); virtual ~Properties(); int length() const; int bitrate() const; int sampleRate() const; int channels() const; ushort lengthInPatterns() const; bool stereo() const; ushort sampleCount() const; ushort patternCount() const; ushort flags() const; ushort trackerVersion() const; ushort fileFormatVersion() const; uchar globalVolume() const; uchar masterVolume() const; uchar tempo() const; uchar bpmSpeed() const; void setChannels(int channels); void setLengthInPatterns (ushort lengthInPatterns); void setStereo (bool stereo); void setSampleCount (ushort sampleCount); void setPatternCount (ushort patternCount); void setFlags (ushort flags); void setTrackerVersion (ushort trackerVersion); void setFileFormatVersion(ushort fileFormatVersion); void setGlobalVolume (uchar globalVolume); void setMasterVolume (uchar masterVolume); void setTempo (uchar tempo); void setBpmSpeed (uchar bpmSpeed); private: Properties(const Properties&); Properties &operator=(const Properties&); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/tag.cpp�������������������������������������������������������������������������0000664�0000000�0000000�00000012624�12225024651�0015511�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tag.h" #include "tstringlist.h" #include "tpropertymap.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); } PropertyMap Tag::properties() const { PropertyMap map; if(!(title().isNull())) map["TITLE"].append(title()); if(!(artist().isNull())) map["ARTIST"].append(artist()); if(!(album().isNull())) map["ALBUM"].append(album()); if(!(comment().isNull())) map["COMMENT"].append(comment()); if(!(genre().isNull())) map["GENRE"].append(genre()); if(!(year() == 0)) map["DATE"].append(String::number(year())); if(!(track() == 0)) map["TRACKNUMBER"].append(String::number(track())); return map; } void Tag::removeUnsupportedProperties(const StringList&) { } PropertyMap Tag::setProperties(const PropertyMap &origProps) { PropertyMap properties(origProps); properties.removeEmpty(); StringList oneValueSet; // can this be simplified by using some preprocessor defines / function pointers? if(properties.contains("TITLE")) { setTitle(properties["TITLE"].front()); oneValueSet.append("TITLE"); } else setTitle(String::null); if(properties.contains("ARTIST")) { setArtist(properties["ARTIST"].front()); oneValueSet.append("ARTIST"); } else setArtist(String::null); if(properties.contains("ALBUM")) { setAlbum(properties["ALBUM"].front()); oneValueSet.append("ALBUM"); } else setAlbum(String::null); if(properties.contains("COMMENT")) { setComment(properties["COMMENT"].front()); oneValueSet.append("COMMENT"); } else setComment(String::null); if(properties.contains("GENRE")) { setGenre(properties["GENRE"].front()); oneValueSet.append("GENRE"); } else setGenre(String::null); if(properties.contains("DATE")) { bool ok; int date = properties["DATE"].front().toInt(&ok); if(ok) { setYear(date); oneValueSet.append("DATE"); } else setYear(0); } else setYear(0); if(properties.contains("TRACKNUMBER")) { bool ok; int track = properties["TRACKNUMBER"].front().toInt(&ok); if(ok) { setTrack(track); oneValueSet.append("TRACKNUMBER"); } else setTrack(0); } else setYear(0); // for each tag that has been set above, remove the first entry in the corresponding // value list. The others will be returned as unsupported by this format. for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) { if(properties[*it].size() == 1) properties.erase(*it); else properties[*it].erase( properties[*it].begin() ); } return properties; } 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()); } } ������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/tag.h���������������������������������������������������������������������������0000664�0000000�0000000�00000015613�12225024651�0015157�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_TAG_H #define TAGLIB_TAG_H #include "taglib_export.h" #include "tstring.h" 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 compliment the generic APIs found * in TagLib::AudioProperties, TagLib::File and TagLib::FileRef. */ class PropertyMap; class TAGLIB_EXPORT Tag { public: /*! * Detroys this Tag instance. */ virtual ~Tag(); /*! * Exports the tags of the file as dictionary mapping (human readable) tag * names (Strings) to StringLists of tag values. * The default implementation in this class considers only the usual built-in * tags (artist, album, ...) and only one value per key. */ PropertyMap properties() const; /*! * Removes unsupported properties, or a subset of them, from the tag. * The parameter \a properties must contain only entries from * properties().unsupportedData(). * BIC: Will become virtual in future releases. Currently the non-virtual * standard implementation of TagLib::Tag does nothing, since there are * no unsupported elements. */ void removeUnsupportedProperties(const StringList& properties); /*! * Sets the tags of this File to those specified in \a properties. This default * implementation sets only the tags for which setter methods exist in this class * (artist, album, ...), and only one value per key; the rest will be contained * in the returned PropertyMap. */ PropertyMap setProperties(const PropertyMap &properties); /*! * 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 comment 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 ���������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/taglib_config.h.cmake�����������������������������������������������������������0000664�0000000�0000000�00000000176�12225024651�0020250�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* taglib_config.h. Generated by cmake from taglib_config.h.cmake */ #define TAGLIB_WITH_ASF 1 #define TAGLIB_WITH_MP4 1 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/taglib_export.h�����������������������������������������������������������������0000664�0000000�0000000�00000004200�12225024651�0017235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_EXPORT_H #define TAGLIB_EXPORT_H #if defined(TAGLIB_STATIC) #define TAGLIB_EXPORT #elif (defined(_WIN32) || defined(_WIN64)) #ifdef MAKE_TAGLIB_LIB #define TAGLIB_EXPORT __declspec(dllexport) #else #define TAGLIB_EXPORT __declspec(dllimport) #endif #elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1) #define TAGLIB_EXPORT __attribute__ ((visibility("default"))) #else #define TAGLIB_EXPORT #endif #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/tagunion.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000012026�12225024651�0016556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tagunion.h" #include "tstringlist.h" using namespace TagLib; #define stringUnion(method) \ if(tag(0) && !tag(0)->method().isEmpty()) \ return tag(0)->method(); \ if(tag(1) && !tag(1)->method().isEmpty()) \ return tag(1)->method(); \ if(tag(2) && !tag(2)->method().isEmpty()) \ return tag(2)->method(); \ return String::null \ #define numberUnion(method) \ if(tag(0) && tag(0)->method() > 0) \ return tag(0)->method(); \ if(tag(1) && tag(1)->method() > 0) \ return tag(1)->method(); \ if(tag(2) && tag(2)->method() > 0) \ return tag(2)->method(); \ return 0 #define setUnion(method, value) \ if(tag(0)) \ tag(0)->set##method(value); \ if(tag(1)) \ tag(1)->set##method(value); \ if(tag(2)) \ tag(2)->set##method(value); \ class TagUnion::TagUnionPrivate { public: TagUnionPrivate() : tags(3, static_cast<Tag *>(0)) { } ~TagUnionPrivate() { delete tags[0]; delete tags[1]; delete tags[2]; } std::vector<Tag *> tags; }; TagUnion::TagUnion(Tag *first, Tag *second, Tag *third) { d = new TagUnionPrivate; d->tags[0] = first; d->tags[1] = second; d->tags[2] = third; } TagUnion::~TagUnion() { delete d; } Tag *TagUnion::operator[](int index) const { return tag(index); } Tag *TagUnion::tag(int index) const { return d->tags[index]; } void TagUnion::set(int index, Tag *tag) { delete d->tags[index]; d->tags[index] = tag; } String TagUnion::title() const { stringUnion(title); } String TagUnion::artist() const { stringUnion(artist); } String TagUnion::album() const { stringUnion(album); } String TagUnion::comment() const { stringUnion(comment); } String TagUnion::genre() const { stringUnion(genre); } TagLib::uint TagUnion::year() const { numberUnion(year); } TagLib::uint TagUnion::track() const { numberUnion(track); } void TagUnion::setTitle(const String &s) { setUnion(Title, s); } void TagUnion::setArtist(const String &s) { setUnion(Artist, s); } void TagUnion::setAlbum(const String &s) { setUnion(Album, s); } void TagUnion::setComment(const String &s) { setUnion(Comment, s); } void TagUnion::setGenre(const String &s) { setUnion(Genre, s); } void TagUnion::setYear(uint i) { setUnion(Year, i); } void TagUnion::setTrack(uint i) { setUnion(Track, i); } bool TagUnion::isEmpty() const { if(d->tags[0] && !d->tags[0]->isEmpty()) return false; if(d->tags[1] && !d->tags[1]->isEmpty()) return false; if(d->tags[2] && !d->tags[2]->isEmpty()) return false; return true; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/tagunion.h����������������������������������������������������������������������0000664�0000000�0000000�00000006304�12225024651�0016225�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_TAGUNION_H #define TAGLIB_TAGUNION_H #include "tag.h" #ifndef DO_NOT_DOCUMENT namespace TagLib { /*! * \internal */ class TagUnion : public Tag { public: enum AccessType { Read, Write }; /*! * Creates a TagLib::Tag that is the union of \a first, \a second, and * \a third. The TagUnion takes ownership of these tags and will handle * their deletion. */ TagUnion(Tag *first = 0, Tag *second = 0, Tag *third = 0); virtual ~TagUnion(); Tag *operator[](int index) const; Tag *tag(int index) const; void set(int index, Tag *tag); 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; template <class T> T *access(int index, bool create) { if(!create || tag(index)) return static_cast<T *>(tag(index)); set(index, new T); return static_cast<T *>(tag(index)); } private: TagUnion(const Tag &); TagUnion &operator=(const Tag &); class TagUnionPrivate; TagUnionPrivate *d; }; } #endif #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015712�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/taglib.h����������������������������������������������������������������0000664�0000000�0000000�00000016417�12225024651�0017336�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_H #define TAGLIB_H #include "taglib_config.h" #define TAGLIB_MAJOR_VERSION 1 #define TAGLIB_MINOR_VERSION 9 #define TAGLIB_PATCH_VERSION 1 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)) #define TAGLIB_IGNORE_MISSING_DESTRUCTOR _Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") #else #define TAGLIB_IGNORE_MISSING_DESTRUCTOR #endif #if (defined(_MSC_VER) && _MSC_VER >= 1600) #define TAGLIB_CONSTRUCT_BITSET(x) static_cast<unsigned long long>(x) #else #define TAGLIB_CONSTRUCT_BITSET(x) static_cast<unsigned long>(x) #endif #include <string> //! A namespace for all TagLib related classes and functions /*! * This namespace contains everything in TagLib. For projects working with * TagLib extensively it may be convenient to add a * \code * using namespace TagLib; * \endcode */ namespace TagLib { class String; typedef wchar_t wchar; // Assumed to be sufficient to store a UTF-16 char. typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long long ulonglong; // long/ulong can be either 32-bit or 64-bit wide. 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<wchar> wstring; } /*! * \mainpage TagLib * * \section intro Introduction * * TagLib is a library for reading and editing audio meta data, commonly know as \e tags. * * Features: * - A clean, high level, C++ API to handling audio meta data. * - Format specific APIs for advanced API users. * - ID3v1, ID3v2, APE, FLAC, Xiph, iTunes-style MP4 and WMA tag formats. * - MP3, MPC, FLAC, MP4, ASF, AIFF, WAV, TrueAudio, WavPack, Ogg FLAC, Ogg Vorbis, Speex and Opus file formats. * - Basic audio file properties such as length, sample rate, etc. * - Long term binary and source compatibility. * - Extensible design, notably the ability to add other formats or extend current formats as a library user. * - Full support for unicode and internationalized tags. * - Dual <a href="http://www.mozilla.org/MPL/MPL-1.1.html">MPL</a> and * <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">LGPL</a> licenses. * - No external toolkit dependancies. * * \section why Why TagLib? * * TagLib originally was written to provide an updated and improved ID3v2 implementation in C++ for use * in a variety of Open Source projects. Since development began in 2002 and the 1.0 release in 2004 * it has expanded to cover a wide variety of tag and file formats and is used in a wide variety of * Open Source and proprietary applications. It now supports a variety of UNIXes, including Apple's OS * X, as well as Microsoft Windows. * * \section commercial Usage in Commercial Applications * * TagLib's licenses \e do allow usage within propriety (\e closed) applications, however TagLib is \e not * public domain. Please note the requirements of the LGPL or MPL, and adhere to at least one of them. * In simple terms, you must at a minimum note your usage of TagLib, note the licensing terms of TagLib and * if you make changes to TagLib publish them. Please review the licenses above before using TagLib in your * software. Note that you may choose either the MPL or the LGPL, you do not have to fulfill the * requirements of both. * * \section installing Installing TagLib * * Please see the <a href="http://developer.kde.org/~wheeler/taglib.html">TagLib website</a> for the latest * downloads. * * TagLib can be built using the CMake build system. TagLib installs a taglib-config and pkg-config file to * make it easier to integrate into various build systems. Note that TagLib's include install directory \e must * be included in the header include path. Simply adding <taglib/tag.h> will \e not work. * * \section start Getting Started * * TagLib provides both simple, abstract APIs which make it possible to ignore the differences between tagging * formats and format specific APIs which allow programmers to work with the features of specific tagging * schemes. There is a similar abstraction mechanism for AudioProperties. * * The best place to start is with the <b>Class Hierarchy</b> linked at the top of the page. The File and * AudioProperties classes and their subclasses are the core of TagLib. The FileRef class is also a convenient * way for using a value-based handle. * * \note When working with FileRef please consider that it has only the most basic (extension-based) file * type resolution. Please see its documentation on how to plug in more advanced file type resolution. (Such * resolution may be part of later TagLib releases by default.) * * Here's a very simple example with TagLib: * * \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 * * More examples can be found in the \e examples directory of the source distribution. * * \section Contact * * Questions about TagLib should be directed to the TagLib mailing list, not directly to the author. * * - <a href="http://developer.kde.org/~wheeler/taglib/">TagLib Homepage</a> * - <a href="https://mail.kde.org/mailman/listinfo/taglib-devel">TagLib Mailing List (taglib-devel@kde.org)</a> * * \author Scott Wheeler <wheeler@kde.org> et al. * */ #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tbytevector.cpp���������������������������������������������������������0000664�0000000�0000000�00000054100�12225024651�0020770�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <algorithm> #include <iostream> #include <cstdio> #include <cstring> #include <tstring.h> #include <tdebug.h> #include "trefcounter.h" #include "tutils.h" #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 efficient. There's more here: // // http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp #define DATA(x) (&(x->data->data[0])) namespace TagLib { static const char hexTable[17] = "0123456789abcdef"; 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 straightforward find that works with the types * std::vector<char>::iterator and std::vector<char>::reverse_iterator. */ template <class TIterator> int findChar( const TIterator dataBegin, const TIterator dataEnd, char c, uint offset, int byteAlign) { const size_t dataSize = dataEnd - dataBegin; if(dataSize == 0 || offset > dataSize - 1) return -1; // n % 0 is invalid if(byteAlign == 0) return -1; for(TIterator it = dataBegin + offset; it < dataEnd; it += byteAlign) { if(*it == c) return (it - dataBegin); } return -1; } /*! * A templatized KMP find that works with the types * std::vector<char>::iterator and std::vector<char>::reverse_iterator. */ template <class TIterator> int findVector( const TIterator dataBegin, const TIterator dataEnd, const TIterator patternBegin, const TIterator patternEnd, uint offset, int byteAlign) { const size_t dataSize = dataEnd - dataBegin; const size_t patternSize = patternEnd - patternBegin; if(patternSize > dataSize || offset > dataSize - 1) return -1; // n % 0 is invalid if(byteAlign == 0) return -1; // Special case that pattern contains just single char. if(patternSize == 1) return findChar(dataBegin, dataEnd, *patternBegin, offset, byteAlign); size_t lastOccurrence[256]; for(size_t i = 0; i < 256; ++i) lastOccurrence[i] = patternSize; for(size_t i = 0; i < patternSize - 1; ++i) lastOccurrence[static_cast<uchar>(*(patternBegin + i))] = patternSize - i - 1; TIterator it = dataBegin + patternSize - 1 + offset; while(true) { TIterator itBuffer = it; TIterator itPattern = patternBegin + patternSize - 1; while(*itBuffer == *itPattern) { if(itPattern == patternBegin) { if((itBuffer - dataBegin - offset) % byteAlign == 0) return (itBuffer - dataBegin); else break; } --itBuffer; --itPattern; } const size_t step = lastOccurrence[static_cast<uchar>(*it)]; if(dataEnd - step <= it) break; it += step; } return -1; } template <class T> T toNumber(const ByteVector &v, size_t offset, size_t length, bool mostSignificantByteFirst) { if(offset >= v.size()) { debug("toNumber<T>() -- No data to convert. Returning 0."); return 0; } length = std::min(length, v.size() - offset); T sum = 0; for(size_t i = 0; i < length; i++) { const size_t shift = (mostSignificantByteFirst ? length - 1 - i : i) * 8; sum |= static_cast<T>(static_cast<uchar>(v[offset + i])) << shift; } return sum; } template <class T> T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) { static const bool isBigEndian = (Utils::SystemByteOrder == Utils::BigEndian); const bool swap = (mostSignificantByteFirst != isBigEndian); if(offset + sizeof(T) > v.size()) return toNumber<T>(v, offset, v.size() - offset, mostSignificantByteFirst); // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. T tmp; ::memcpy(&tmp, v.data() + offset, sizeof(T)); if(swap) return Utils::byteSwap(tmp); else return tmp; } template <class T> ByteVector fromNumber(T value, bool mostSignificantByteFirst) { static const bool isBigEndian = (Utils::SystemByteOrder == Utils::BigEndian); const bool swap = (mostSignificantByteFirst != isBigEndian); if(swap) value = Utils::byteSwap(value); return ByteVector(reinterpret_cast<const char *>(&value), sizeof(T)); } class DataPrivate : public RefCounter { public: DataPrivate() { } DataPrivate(const std::vector<char> &v, uint offset, uint length) : data(v.begin() + offset, v.begin() + offset + length) { } // A char* can be an iterator. DataPrivate(const char *begin, const char *end) : data(begin, end) { } DataPrivate(uint len, char c) : data(len, c) { } std::vector<char> data; }; class ByteVector::ByteVectorPrivate : public RefCounter { public: ByteVectorPrivate() : RefCounter() , data(new DataPrivate()) , offset(0) , length(0) { } ByteVectorPrivate(ByteVectorPrivate *d, uint o, uint l) : RefCounter() , data(d->data) , offset(d->offset + o) , length(l) { data->ref(); } ByteVectorPrivate(const std::vector<char> &v, uint o, uint l) : RefCounter() , data(new DataPrivate(v, o, l)) , offset(0) , length(l) { } ByteVectorPrivate(uint l, char c) : RefCounter() , data(new DataPrivate(l, c)) , offset(0) , length(l) { } ByteVectorPrivate(const char *s, uint l) : RefCounter() , data(new DataPrivate(s, s + l)) , offset(0) , length(l) { } void detach() { if(data->count() > 1) { data->deref(); data = new DataPrivate(data->data, offset, length); offset = 0; } } ~ByteVectorPrivate() { if(data->deref()) delete data; } ByteVectorPrivate &operator=(const ByteVectorPrivate &x) { if(&x != this) { if(data->deref()) delete data; data = x.data; data->ref(); } return *this; } DataPrivate *data; uint offset; uint length; }; //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// ByteVector ByteVector::null; ByteVector ByteVector::fromCString(const char *s, uint length) { if(length == 0xffffffff) return ByteVector(s, ::strlen(s)); else return ByteVector(s, length); } ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) { return fromNumber<uint>(value, mostSignificantByteFirst); } ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) { return fromNumber<ushort>(value, mostSignificantByteFirst); } ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) { return fromNumber<unsigned long long>(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(const ByteVector &v, uint offset, uint length) : d(new ByteVectorPrivate(v.d, offset, length)) { } ByteVector::ByteVector(char c) : d(new ByteVectorPrivate(1, c)) { } ByteVector::ByteVector(const char *data, uint length) : d(new ByteVectorPrivate(data, length)) { } ByteVector::ByteVector(const char *data) : d(new ByteVectorPrivate(data, ::strlen(data))) { } ByteVector::~ByteVector() { if(d->deref()) delete d; } ByteVector &ByteVector::setData(const char *s, uint length) { *this = ByteVector(s, length); return *this; } ByteVector &ByteVector::setData(const char *data) { *this = ByteVector(data); return *this; } char *ByteVector::data() { detach(); return size() > 0 ? (DATA(d) + d->offset) : 0; } const char *ByteVector::data() const { return size() > 0 ? (DATA(d) + d->offset) : 0; } ByteVector ByteVector::mid(uint index, uint length) const { index = std::min(index, size()); length = std::min(length, size() - index); return ByteVector(*this, index, length); } char ByteVector::at(uint index) const { return index < size() ? DATA(d)[d->offset + index] : 0; } int ByteVector::find(const ByteVector &pattern, uint offset, int byteAlign) const { return findVector<ConstIterator>( begin(), end(), pattern.begin(), pattern.end(), offset, byteAlign); } int ByteVector::find(char c, uint offset, int byteAlign) const { return findChar<ConstIterator>(begin(), end(), c, offset, byteAlign); } int ByteVector::rfind(const ByteVector &pattern, uint offset, int byteAlign) const { if(offset > 0) { offset = size() - offset - pattern.size(); if(offset >= size()) offset = 0; } const int pos = findVector<ConstReverseIterator>( rbegin(), rend(), pattern.rbegin(), pattern.rend(), offset, byteAlign); if(pos == -1) return -1; else return size() - pos - pattern.size(); } 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 const uint compareLength = patternLength - patternOffset; if(offset + compareLength > size() || patternOffset >= pattern.size() || patternLength == 0) return false; return (::memcmp(data() + offset, pattern.data() + patternOffset, compareLength) == 0); } bool ByteVector::startsWith(const ByteVector &pattern) const { return containsAt(pattern, 0); } bool ByteVector::endsWith(const ByteVector &pattern) const { return containsAt(pattern, size() - pattern.size()); } ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &with) { if(pattern.size() == 0 || pattern.size() > size()) return *this; const uint withSize = with.size(); const uint patternSize = pattern.size(); int offset = 0; if(withSize == patternSize) { // I think this case might be common enough to optimize it detach(); offset = find(pattern); while(offset >= 0) { ::memcpy(data() + offset, with.data(), withSize); offset = find(pattern, offset + withSize); } return *this; } // calculate new size: uint newSize = 0; for(;;) { int next = find(pattern, offset); if(next < 0) { if(offset == 0) // pattern not found, do nothing: return *this; newSize += size() - offset; break; } newSize += (next - offset) + withSize; offset = next + patternSize; } // new private data of appropriate size: ByteVectorPrivate *newData = new ByteVectorPrivate(newSize, 0); char *target = DATA(newData); const char *source = data(); // copy modified data into new private data: offset = 0; for(;;) { int next = find(pattern, offset); if(next < 0) { ::memcpy(target, source + offset, size() - offset); break; } int chunkSize = next - offset; ::memcpy(target, source + offset, chunkSize); target += chunkSize; ::memcpy(target, with.data(), withSize); target += withSize; offset += chunkSize + patternSize; } // replace private data: if(d->deref()) delete d; d = newData; return *this; } 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; } ByteVector &ByteVector::append(const ByteVector &v) { if(v.d->length != 0) { detach(); uint originalSize = size(); resize(originalSize + v.size()); ::memcpy(data() + originalSize, v.data(), v.size()); } return *this; } ByteVector &ByteVector::clear() { *this = ByteVector(); return *this; } TagLib::uint ByteVector::size() const { return d->length; } ByteVector &ByteVector::resize(uint size, char padding) { if(size != d->length) { detach(); d->data->data.resize(d->offset + size, padding); d->length = size; } return *this; } ByteVector::Iterator ByteVector::begin() { return d->data->data.begin() + d->offset; } ByteVector::ConstIterator ByteVector::begin() const { return d->data->data.begin() + d->offset; } ByteVector::Iterator ByteVector::end() { return d->data->data.begin() + d->offset + d->length; } ByteVector::ConstIterator ByteVector::end() const { return d->data->data.begin() + d->offset + d->length; } ByteVector::ReverseIterator ByteVector::rbegin() { std::vector<char> &v = d->data->data; return v.rbegin() + (v.size() - (d->offset + d->length)); } ByteVector::ConstReverseIterator ByteVector::rbegin() const { std::vector<char> &v = d->data->data; return v.rbegin() + (v.size() - (d->offset + d->length)); } ByteVector::ReverseIterator ByteVector::rend() { std::vector<char> &v = d->data->data; return v.rbegin() + (v.size() - d->offset); } ByteVector::ConstReverseIterator ByteVector::rend() const { std::vector<char> &v = d->data->data; return v.rbegin() + (v.size() - d->offset); } bool ByteVector::isNull() const { return (d == null.d); } bool ByteVector::isEmpty() const { return (d->length == 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<uint>(*this, 0, mostSignificantByteFirst); } TagLib::uint ByteVector::toUInt(uint offset, bool mostSignificantByteFirst) const { return toNumber<uint>(*this, offset, mostSignificantByteFirst); } TagLib::uint ByteVector::toUInt(uint offset, uint length, bool mostSignificantByteFirst) const { return toNumber<uint>(*this, offset, length, mostSignificantByteFirst); } short ByteVector::toShort(bool mostSignificantByteFirst) const { return toNumber<unsigned short>(*this, 0, mostSignificantByteFirst); } short ByteVector::toShort(uint offset, bool mostSignificantByteFirst) const { return toNumber<unsigned short>(*this, offset, mostSignificantByteFirst); } unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const { return toNumber<unsigned short>(*this, 0, mostSignificantByteFirst); } unsigned short ByteVector::toUShort(uint offset, bool mostSignificantByteFirst) const { return toNumber<unsigned short>(*this, offset, mostSignificantByteFirst); } long long ByteVector::toLongLong(bool mostSignificantByteFirst) const { return toNumber<unsigned long long>(*this, 0, mostSignificantByteFirst); } long long ByteVector::toLongLong(uint offset, bool mostSignificantByteFirst) const { return toNumber<unsigned long long>(*this, offset, mostSignificantByteFirst); } const char &ByteVector::operator[](int index) const { return d->data->data[d->offset + index]; } char &ByteVector::operator[](int index) { detach(); return d->data->data[d->offset + index]; } bool ByteVector::operator==(const ByteVector &v) const { if(size() != v.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(size() != ::strlen(s)) return false; return (::memcmp(data(), s, size()) == 0); } bool ByteVector::operator!=(const char *s) const { return !operator==(s); } bool ByteVector::operator<(const ByteVector &v) const { const int result = ::memcmp(data(), v.data(), std::min(size(), v.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) { *this = ByteVector(c); return *this; } ByteVector &ByteVector::operator=(const char *data) { *this = ByteVector(data); return *this; } ByteVector ByteVector::toHex() const { ByteVector encoded(size() * 2); char *p = encoded.data(); for(uint i = 0; i < size(); i++) { unsigned char c = data()[i]; *p++ = hexTable[(c >> 4) & 0x0F]; *p++ = hexTable[(c ) & 0x0F]; } return encoded; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void ByteVector::detach() { if(d->data->count() > 1) { d->data->deref(); d->data = new DataPrivate(d->data->data, d->offset, d->length); d->offset = 0; } if(d->count() > 1) { d->deref(); d = new ByteVectorPrivate(d->data->data, d->offset, d->length); } } } //////////////////////////////////////////////////////////////////////////////// // related functions //////////////////////////////////////////////////////////////////////////////// std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v) { for(TagLib::uint i = 0; i < v.size(); i++) s << v[i]; return s; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tbytevector.h�����������������������������������������������������������0000664�0000000�0000000�00000042455�12225024651�0020447�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_BYTEVECTOR_H #define TAGLIB_BYTEVECTOR_H #include "taglib.h" #include "taglib_export.h" #include <vector> #include <iostream> 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 TAGLIB_EXPORT ByteVector { public: #ifndef DO_NOT_DOCUMENT typedef std::vector<char>::iterator Iterator; typedef std::vector<char>::const_iterator ConstIterator; typedef std::vector<char>::reverse_iterator ReverseIterator; typedef std::vector<char>::const_reverse_iterator ConstReverseIterator; #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); /*! * Constructs a byte vector that is a copy of \a v. */ ByteVector(const ByteVector &v); /*! * Constructs a byte vector that is a copy of \a v. */ ByteVector(const ByteVector &v, uint offset, uint length); /*! * Constructs 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 */ ByteVector &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. */ ByteVector &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 byte divisible * by \a byteAlign (starting from \a offset). */ int find(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; /*! * Searches the char for \a c starting at \a offset and returns * the offset. Returns \a npos if the pattern was not found. If \a byteAlign is * specified the pattern will only be matched if it starts on a byte divisible * by \a byteAlign (starting from \a offset). */ int find(char c, 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 byte divisible by \a byteAlign (starting from \a offset). */ 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; /*! * Replaces \a pattern with \a with and returns a reference to the ByteVector * after the operation. This \e does modify the vector. */ ByteVector &replace(const ByteVector &pattern, const ByteVector &with); /*! * 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. */ ByteVector &append(const ByteVector &v); /*! * Clears the data. */ ByteVector &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 a ReverseIterator that points to the front of the vector. */ ReverseIterator rbegin(); /*! * Returns a ConstReverseIterator that points to the front of the vector. */ ConstReverseIterator rbegin() const; /*! * Returns a ReverseIterator that points to the back of the vector. */ ReverseIterator rend(); /*! * Returns a ConstReverseIterator that points to the back of the vector. */ ConstReverseIterator rend() 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 4 bytes at \a offset 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(uint offset, bool mostSignificantByteFirst = true) const; /*! * Converts the \a length bytes at \a offset of the vector to an unsigned * integer. If \a length is larger than 4, the excess is ignored. * * 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(uint offset, uint length, bool mostSignificantByteFirst = true) const; /*! * Converts the first 2 bytes of the vector to a (signed) 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 2 bytes at \a offset of the vector to a (signed) 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(uint offset, bool mostSignificantByteFirst = true) const; /*! * Converts the first 2 bytes of the vector to a unsigned 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() */ unsigned short toUShort(bool mostSignificantByteFirst = true) const; /*! * Converts the 2 bytes at \a offset of the vector to a unsigned 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() */ unsigned short toUShort(uint offset, 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; /*! * Converts the 8 bytes at \a offset 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(uint offset, 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; /*! * Returns a hex-encoded copy of the byte vector. */ ByteVector toHex() const; 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. */ TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tbytevectorlist.cpp�����������������������������������������������������0000664�0000000�0000000�00000006622�12225024651�0021672�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tbytevectorlist.h" using namespace TagLib; class ByteVectorListPrivate { }; //////////////////////////////////////////////////////////////////////////////// // static members //////////////////////////////////////////////////////////////////////////////// ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, int byteAlign) { return split(v, pattern, byteAlign, 0); } ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, int byteAlign, int max) { ByteVectorList l; uint previousOffset = 0; for(int offset = v.find(pattern, 0, byteAlign); offset != -1 && (max == 0 || max > int(l.size()) + 1); offset = v.find(pattern, offset + pattern.size(), byteAlign)) { if(offset - previousOffset >= 1) l.append(v.mid(previousOffset, offset - previousOffset)); else l.append(ByteVector::null); previousOffset = offset + pattern.size(); } if(previousOffset < v.size()) l.append(v.mid(previousOffset, v.size() - previousOffset)); return l; } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// ByteVectorList::ByteVectorList() : List<ByteVector>() { } ByteVectorList::ByteVectorList(const ByteVectorList &l) : List<ByteVector>(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; } ��������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tbytevectorlist.h�������������������������������������������������������0000664�0000000�0000000�00000007017�12225024651�0021336�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_BYTEVECTORLIST_H #define TAGLIB_BYTEVECTORLIST_H #include "taglib_export.h" #include "tbytevector.h" #include "tlist.h" namespace TagLib { //! A list of ByteVectors /*! * A List specialization with some handy features useful for ByteVectors. */ class TAGLIB_EXPORT ByteVectorList : public List<ByteVector> { 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); /*! * Splits the ByteVector \a v into several strings at \a pattern. This will * not include the pattern in the returned ByteVectors. \a max is the * maximum number of entries that will be separated. If \a max for instance * is 2 then a maximum of 1 match will be found and the vector will be split * on that match. */ // BIC: merge with the function above static ByteVectorList split(const ByteVector &v, const ByteVector &pattern, int byteAlign, int max); private: class ByteVectorListPrivate; ByteVectorListPrivate *d; }; } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tbytevectorstream.cpp���������������������������������������������������0000664�0000000�0000000�00000011053�12225024651�0022204�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Lukas Lalinsky email : lalinsky@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tbytevectorstream.h" #include "tstring.h" #include "tdebug.h" #include <stdio.h> #include <string.h> #include <stdlib.h> using namespace TagLib; class ByteVectorStream::ByteVectorStreamPrivate { public: ByteVectorStreamPrivate(const ByteVector &data); ByteVector data; long position; }; ByteVectorStream::ByteVectorStreamPrivate::ByteVectorStreamPrivate(const ByteVector &data) : data(data), position(0) { } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// ByteVectorStream::ByteVectorStream(const ByteVector &data) { d = new ByteVectorStreamPrivate(data); } ByteVectorStream::~ByteVectorStream() { delete d; } FileName ByteVectorStream::name() const { return FileName(""); // XXX do we need a name? } ByteVector ByteVectorStream::readBlock(ulong length) { if(length == 0) return ByteVector::null; ByteVector v = d->data.mid(d->position, length); d->position += v.size(); return v; } void ByteVectorStream::writeBlock(const ByteVector &data) { uint size = data.size(); if(long(d->position + size) > length()) { truncate(d->position + size); } memcpy(d->data.data() + d->position, data.data(), size); d->position += size; } void ByteVectorStream::insert(const ByteVector &data, ulong start, ulong replace) { long sizeDiff = data.size() - replace; if(sizeDiff < 0) { removeBlock(start + data.size(), -sizeDiff); } else if(sizeDiff > 0) { truncate(length() + sizeDiff); ulong readPosition = start + replace; ulong writePosition = start + data.size(); memmove(d->data.data() + writePosition, d->data.data() + readPosition, length() - sizeDiff - readPosition); } seek(start); writeBlock(data); } void ByteVectorStream::removeBlock(ulong start, ulong length) { ulong readPosition = start + length; ulong writePosition = start; if(readPosition < ulong(ByteVectorStream::length())) { ulong bytesToMove = ByteVectorStream::length() - readPosition; memmove(d->data.data() + writePosition, d->data.data() + readPosition, bytesToMove); writePosition += bytesToMove; } d->position = writePosition; truncate(writePosition); } bool ByteVectorStream::readOnly() const { return false; } bool ByteVectorStream::isOpen() const { return true; } void ByteVectorStream::seek(long offset, Position p) { switch(p) { case Beginning: d->position = offset; break; case Current: d->position += offset; break; case End: d->position = length() - offset; break; } } void ByteVectorStream::clear() { } long ByteVectorStream::tell() const { return d->position; } long ByteVectorStream::length() { return d->data.size(); } void ByteVectorStream::truncate(long length) { d->data.resize(length); } ByteVector *ByteVectorStream::data() { return &d->data; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tbytevectorstream.h�����������������������������������������������������0000664�0000000�0000000�00000011224�12225024651�0021651�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Lukas Lalinsky email : lalinsky@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_BYTEVECTORSTREAM_H #define TAGLIB_BYTEVECTORSTREAM_H #include "taglib_export.h" #include "taglib.h" #include "tbytevector.h" #include "tiostream.h" namespace TagLib { class String; class Tag; class AudioProperties; //! In-memory Stream class using ByteVector for its storage. class TAGLIB_EXPORT ByteVectorStream : public IOStream { public: /*! * Construct a File object and opens the \a file. \a file should be a * be a C-string in the local file system encoding. */ ByteVectorStream(const ByteVector &data); /*! * Destroys this ByteVectorStream instance. */ virtual ~ByteVectorStream(); /*! * Returns the file name in the local file system encoding. */ FileName name() const; /*! * 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); /*! * 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; /*! * 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 within the file. */ long tell() const; /*! * Returns the length of the file. */ long length(); /*! * Truncates the file to a \a length. */ void truncate(long length); ByteVector *data(); protected: private: class ByteVectorStreamPrivate; ByteVectorStreamPrivate *d; }; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tdebug.cpp��������������������������������������������������������������0000664�0000000�0000000�00000005635�12225024651�0017701�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include "tdebug.h" #include "tstring.h" #include "tdebuglistener.h" #include <bitset> #include <cstdio> #include <cstdarg> using namespace TagLib; namespace { String format(const char *fmt, ...) { va_list args; va_start(args, fmt); char buf[256]; #if defined(HAVE_SNPRINTF) vsnprintf(buf, sizeof(buf), fmt, args); #elif defined(HAVE_SPRINTF_S) vsprintf_s(buf, fmt, args); #else // Be careful. May cause a buffer overflow. vsprintf(buf, fmt, args); #endif va_end(args); return String(buf); } } namespace TagLib { // The instance is defined in tdebuglistener.cpp. extern DebugListener *debugListener; void debug(const String &s) { #if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) debugListener->printMessage("TagLib: " + s + "\n"); #endif } void debugData(const ByteVector &v) { #if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) for(size_t i = 0; i < v.size(); ++i) { std::string bits = std::bitset<8>(v[i]).to_string(); String msg = format("*** [%d] - char '%c' - int %d, 0x%02x, 0b%s\n", i, v[i], v[i], v[i], bits.c_str()); debugListener->printMessage(msg); } #endif } } ���������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tdebug.h����������������������������������������������������������������0000664�0000000�0000000�00000005012�12225024651�0017333�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_DEBUG_H #define TAGLIB_DEBUG_H namespace TagLib { class String; class ByteVector; #ifndef DO_NOT_DOCUMENT /*! * A simple function that outputs the debug messages to the listener. * The default listener redirects the messages to \a stderr when NDEBUG is * not defined. * * \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); } #endif #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tdebuglistener.cpp������������������������������������������������������0000664�0000000�0000000�00000005261�12225024651�0021442�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2013 by Tsuda Kageyu email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tdebuglistener.h" #include <iostream> #include <bitset> #ifdef _WIN32 # include <windows.h> #endif using namespace TagLib; namespace { class DefaultListener : public DebugListener { public: virtual void printMessage(const String &msg) { #ifdef _WIN32 const wstring wstr = msg.toWString(); const int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL); if(len != 0) { std::vector<char> buf(len); WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &buf[0], len, NULL, NULL); std::cerr << std::string(&buf[0]); } #else std::cerr << msg; #endif } }; DefaultListener defaultListener; } namespace TagLib { DebugListener *debugListener = &defaultListener; DebugListener::DebugListener() { } DebugListener::~DebugListener() { } void setDebugListener(DebugListener *listener) { if(listener) debugListener = listener; else debugListener = &defaultListener; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tdebuglistener.h��������������������������������������������������������0000664�0000000�0000000�00000005765�12225024651�0021120�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2013 by Tsuda Kageyu email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_DEBUGLISTENER_H #define TAGLIB_DEBUGLISTENER_H #include "taglib_export.h" #include "tstring.h" namespace TagLib { //! An abstraction for the listener to the debug messages. /*! * This class enables you to handle the debug messages in your preferred * way by subclassing this class, reimplementing printMessage() and setting * your reimplementation as the default with setDebugListener(). * * \see setDebugListener() */ class TAGLIB_EXPORT DebugListener { public: DebugListener(); virtual ~DebugListener(); /*! * When overridden in a derived class, redirects \a msg to your preferred * channel such as stderr, Windows debugger or so forth. */ virtual void printMessage(const String &msg) = 0; private: // Noncopyable DebugListener(const DebugListener &); DebugListener &operator=(const DebugListener &); }; /*! * Sets the listener that decides how the debug messages are redirected. * If the parameter \a listener is null, the previous listener is released * and default stderr listener is restored. * * \note The caller is responsible for deleting the previous listener * as needed after it is released. * * \see DebugListener */ TAGLIB_EXPORT void setDebugListener(DebugListener *listener); } #endif �����������taglib-1.9.1/taglib/toolkit/tfile.cpp���������������������������������������������������������������0000664�0000000�0000000�00000036207�12225024651�0017531�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tfile.h" #include "tfilestream.h" #include "tstring.h" #include "tdebug.h" #include "tpropertymap.h" #ifdef _WIN32 # include <windows.h> # include <io.h> #else # include <stdio.h> # include <unistd.h> #endif #ifndef R_OK # define R_OK 4 #endif #ifndef W_OK # define W_OK 2 #endif #include "asffile.h" #include "mpegfile.h" #include "vorbisfile.h" #include "flacfile.h" #include "oggflacfile.h" #include "mpcfile.h" #include "mp4file.h" #include "wavpackfile.h" #include "speexfile.h" #include "opusfile.h" #include "trueaudiofile.h" #include "aifffile.h" #include "wavfile.h" #include "apefile.h" #include "modfile.h" #include "s3mfile.h" #include "itfile.h" #include "xmfile.h" #include "mp4file.h" using namespace TagLib; namespace { #ifdef _WIN32 const TagLib::uint BufferSize = 8192; #else const TagLib::uint BufferSize = 1024; #endif } class File::FilePrivate { public: FilePrivate(IOStream *stream, bool owner); IOStream *stream; bool streamOwner; bool valid; }; File::FilePrivate::FilePrivate(IOStream *stream, bool owner) : stream(stream), streamOwner(owner), valid(true) { } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// File::File(FileName fileName) { IOStream *stream = new FileStream(fileName); d = new FilePrivate(stream, true); } File::File(IOStream *stream) { d = new FilePrivate(stream, false); } File::~File() { if(d->stream && d->streamOwner) delete d->stream; delete d; } FileName File::name() const { return d->stream->name(); } PropertyMap File::properties() const { // ugly workaround until this method is virtual if(dynamic_cast<const APE::File* >(this)) return dynamic_cast<const APE::File* >(this)->properties(); if(dynamic_cast<const FLAC::File* >(this)) return dynamic_cast<const FLAC::File* >(this)->properties(); if(dynamic_cast<const IT::File* >(this)) return dynamic_cast<const IT::File* >(this)->properties(); if(dynamic_cast<const Mod::File* >(this)) return dynamic_cast<const Mod::File* >(this)->properties(); if(dynamic_cast<const MPC::File* >(this)) return dynamic_cast<const MPC::File* >(this)->properties(); if(dynamic_cast<const MPEG::File* >(this)) return dynamic_cast<const MPEG::File* >(this)->properties(); if(dynamic_cast<const Ogg::FLAC::File* >(this)) return dynamic_cast<const Ogg::FLAC::File* >(this)->properties(); if(dynamic_cast<const Ogg::Speex::File* >(this)) return dynamic_cast<const Ogg::Speex::File* >(this)->properties(); if(dynamic_cast<const Ogg::Opus::File* >(this)) return dynamic_cast<const Ogg::Opus::File* >(this)->properties(); if(dynamic_cast<const Ogg::Vorbis::File* >(this)) return dynamic_cast<const Ogg::Vorbis::File* >(this)->properties(); if(dynamic_cast<const RIFF::AIFF::File* >(this)) return dynamic_cast<const RIFF::AIFF::File* >(this)->properties(); if(dynamic_cast<const RIFF::WAV::File* >(this)) return dynamic_cast<const RIFF::WAV::File* >(this)->properties(); if(dynamic_cast<const S3M::File* >(this)) return dynamic_cast<const S3M::File* >(this)->properties(); if(dynamic_cast<const TrueAudio::File* >(this)) return dynamic_cast<const TrueAudio::File* >(this)->properties(); if(dynamic_cast<const WavPack::File* >(this)) return dynamic_cast<const WavPack::File* >(this)->properties(); if(dynamic_cast<const XM::File* >(this)) return dynamic_cast<const XM::File* >(this)->properties(); if(dynamic_cast<const MP4::File* >(this)) return dynamic_cast<const MP4::File* >(this)->properties(); if(dynamic_cast<const ASF::File* >(this)) return dynamic_cast<const ASF::File* >(this)->properties(); return tag()->properties(); } void File::removeUnsupportedProperties(const StringList &properties) { // here we only consider those formats that could possibly contain // unsupported properties if(dynamic_cast<APE::File* >(this)) dynamic_cast<APE::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<FLAC::File* >(this)) dynamic_cast<FLAC::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<MPC::File* >(this)) dynamic_cast<MPC::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<MPEG::File* >(this)) dynamic_cast<MPEG::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<Ogg::Vorbis::File* >(this)) dynamic_cast<Ogg::Vorbis::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<RIFF::AIFF::File* >(this)) dynamic_cast<RIFF::AIFF::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<RIFF::WAV::File* >(this)) dynamic_cast<RIFF::WAV::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<TrueAudio::File* >(this)) dynamic_cast<TrueAudio::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<WavPack::File* >(this)) dynamic_cast<WavPack::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<MP4::File* >(this)) dynamic_cast<MP4::File* >(this)->removeUnsupportedProperties(properties); else if(dynamic_cast<ASF::File* >(this)) dynamic_cast<ASF::File* >(this)->removeUnsupportedProperties(properties); else tag()->removeUnsupportedProperties(properties); } PropertyMap File::setProperties(const PropertyMap &properties) { if(dynamic_cast<APE::File* >(this)) return dynamic_cast<APE::File* >(this)->setProperties(properties); else if(dynamic_cast<FLAC::File* >(this)) return dynamic_cast<FLAC::File* >(this)->setProperties(properties); else if(dynamic_cast<IT::File* >(this)) return dynamic_cast<IT::File* >(this)->setProperties(properties); else if(dynamic_cast<Mod::File* >(this)) return dynamic_cast<Mod::File* >(this)->setProperties(properties); else if(dynamic_cast<MPC::File* >(this)) return dynamic_cast<MPC::File* >(this)->setProperties(properties); else if(dynamic_cast<MPEG::File* >(this)) return dynamic_cast<MPEG::File* >(this)->setProperties(properties); else if(dynamic_cast<Ogg::FLAC::File* >(this)) return dynamic_cast<Ogg::FLAC::File* >(this)->setProperties(properties); else if(dynamic_cast<Ogg::Speex::File* >(this)) return dynamic_cast<Ogg::Speex::File* >(this)->setProperties(properties); else if(dynamic_cast<Ogg::Opus::File* >(this)) return dynamic_cast<Ogg::Opus::File* >(this)->setProperties(properties); else if(dynamic_cast<Ogg::Vorbis::File* >(this)) return dynamic_cast<Ogg::Vorbis::File* >(this)->setProperties(properties); else if(dynamic_cast<RIFF::AIFF::File* >(this)) return dynamic_cast<RIFF::AIFF::File* >(this)->setProperties(properties); else if(dynamic_cast<RIFF::WAV::File* >(this)) return dynamic_cast<RIFF::WAV::File* >(this)->setProperties(properties); else if(dynamic_cast<S3M::File* >(this)) return dynamic_cast<S3M::File* >(this)->setProperties(properties); else if(dynamic_cast<TrueAudio::File* >(this)) return dynamic_cast<TrueAudio::File* >(this)->setProperties(properties); else if(dynamic_cast<WavPack::File* >(this)) return dynamic_cast<WavPack::File* >(this)->setProperties(properties); else if(dynamic_cast<XM::File* >(this)) return dynamic_cast<XM::File* >(this)->setProperties(properties); else if(dynamic_cast<MP4::File* >(this)) return dynamic_cast<MP4::File* >(this)->setProperties(properties); else if(dynamic_cast<ASF::File* >(this)) return dynamic_cast<ASF::File* >(this)->setProperties(properties); else return tag()->setProperties(properties); } ByteVector File::readBlock(ulong length) { return d->stream->readBlock(length); } void File::writeBlock(const ByteVector &data) { d->stream->writeBlock(data); } long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before) { if(!d->stream || pattern.size() > 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(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { // (1) previous partial match if(previousPartialMatch >= 0 && int(bufferSize()) > previousPartialMatch) { const int patternOffset = (bufferSize() - previousPartialMatch); if(buffer.containsAt(pattern, 0, patternOffset)) { seek(originalPosition); return bufferOffset - bufferSize() + previousPartialMatch; } } if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(bufferSize()) > beforePreviousPartialMatch) { const int beforeOffset = (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 += 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->stream || pattern.size() > 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(bufferSize()), End); bufferOffset = tell(); } else { seek(fromOffset + -1 * int(bufferSize()), Beginning); bufferOffset = tell(); } // See the notes in find() for an explanation of this algorithm. for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(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 -= 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) { d->stream->insert(data, start, replace); } void File::removeBlock(ulong start, ulong length) { d->stream->removeBlock(start, length); } bool File::readOnly() const { return d->stream->readOnly(); } bool File::isOpen() const { return d->stream->isOpen(); } bool File::isValid() const { return isOpen() && d->valid; } void File::seek(long offset, Position p) { d->stream->seek(offset, IOStream::Position(p)); } void File::truncate(long length) { d->stream->truncate(length); } void File::clear() { d->stream->clear(); } long File::tell() const { return d->stream->tell(); } long File::length() { return d->stream->length(); } bool File::isReadable(const char *file) { #if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later return _access_s(file, R_OK) == 0; #else return access(file, R_OK) == 0; #endif } bool File::isWritable(const char *file) { #if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later return _access_s(file, W_OK) == 0; #else return access(file, W_OK) == 0; #endif } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// TagLib::uint File::bufferSize() { return BufferSize; } void File::setValid(bool valid) { d->valid = valid; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tfile.h�����������������������������������������������������������������0000664�0000000�0000000�00000025300�12225024651�0017166�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FILE_H #define TAGLIB_FILE_H #include "taglib_export.h" #include "taglib.h" #include "tag.h" #include "tbytevector.h" #include "tiostream.h" namespace TagLib { class String; class Tag; class AudioProperties; class PropertyMap; //! 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 TAGLIB_EXPORT 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. */ FileName name() const; /*! * Returns a pointer to this file's tag. This should be reimplemented in * the concrete subclasses. */ virtual Tag *tag() const = 0; /*! * Exports the tags of the file as dictionary mapping (human readable) tag * names (uppercase Strings) to StringLists of tag values. Calls the according * specialization in the File subclasses. * For each metadata object of the file that could not be parsed into the PropertyMap * format, the returend map's unsupportedData() list will contain one entry identifying * that object (e.g. the frame type for ID3v2 tags). Use removeUnsupportedProperties() * to remove (a subset of) them. * For files that contain more than one tag (e.g. an MP3 with both an ID3v2 and an ID3v2 * tag) only the most "modern" one will be exported (ID3v2 in this case). * BIC: Will be made virtual in future releases. */ PropertyMap properties() const; /*! * Removes unsupported properties, or a subset of them, from the file's metadata. * The parameter \a properties must contain only entries from * properties().unsupportedData(). * BIC: Will be mad virtual in future releases. */ void removeUnsupportedProperties(const StringList& properties); /*! * Sets the tags of this File to those specified in \a properties. Calls the * according specialization method in the subclasses of File to do the translation * into the format-specific details. * If some value(s) could not be written imported to the specific metadata format, * the returned PropertyMap will contain those value(s). Otherwise it will be empty, * indicating that no problems occured. * With file types that support several tag formats (for instance, MP3 files can have * ID3v1, ID3v2, and APEv2 tags), this function will create the most appropriate one * (ID3v2 for MP3 files). Older formats will be updated as well, if they exist, but won't * be taken into account for the return value of this function. * See the documentation of the subclass implementations for detailed descriptions. * BIC: will become pure virtual in the future */ PropertyMap setProperties(const PropertyMap &properties); /*! * 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. * * \warning On UNIX multiple processes are able to write to the same file at * the same time. This can result in serious file corruption. If you are * developing a program that makes use of TagLib from multiple processes you * must insure that you are only doing writes to a particular file from one * of them. */ 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 readable. */ 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 within 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. * * \deprecated */ static bool isReadable(const char *file); /*! * Returns true if \a file can be opened for writing. * * \deprecated */ 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(FileName file); /*! * Construct a File object and use the \a stream instance. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note Constructor is protected since this class should only be * instantiated through subclasses. */ File(IOStream *stream); /*! * 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 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tfilestream.cpp���������������������������������������������������������0000664�0000000�0000000�00000026274�12225024651�0020750�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tfilestream.h" #include "tstring.h" #include "tdebug.h" #ifdef _WIN32 # include <windows.h> #else # include <stdio.h> # include <unistd.h> #endif using namespace TagLib; namespace { #ifdef _WIN32 // Uses Win32 native API instead of POSIX API to reduce the resource consumption. typedef FileName FileNameHandle; typedef HANDLE FileHandle; const TagLib::uint BufferSize = 8192; const FileHandle InvalidFileHandle = INVALID_HANDLE_VALUE; inline FileHandle openFile(const FileName &path, bool readOnly) { const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); if(!path.wstr().empty()) return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); else if(!path.str().empty()) return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); else return InvalidFileHandle; } inline void closeFile(FileHandle file) { CloseHandle(file); } inline size_t readFile(FileHandle file, ByteVector &buffer) { DWORD length; if(ReadFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL)) return static_cast<size_t>(length); else return 0; } inline size_t writeFile(FileHandle file, const ByteVector &buffer) { DWORD length; if(WriteFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL)) return static_cast<size_t>(length); else return 0; } #else // _WIN32 struct FileNameHandle : public std::string { FileNameHandle(FileName name) : std::string(name) {} operator FileName () const { return c_str(); } }; typedef FILE* FileHandle; const TagLib::uint BufferSize = 8192; const FileHandle InvalidFileHandle = 0; inline FileHandle openFile(const FileName &path, bool readOnly) { return fopen(path, readOnly ? "rb" : "rb+"); } inline void closeFile(FileHandle file) { fclose(file); } inline size_t readFile(FileHandle file, ByteVector &buffer) { return fread(buffer.data(), sizeof(char), buffer.size(), file); } inline size_t writeFile(FileHandle file, const ByteVector &buffer) { return fwrite(buffer.data(), sizeof(char), buffer.size(), file); } #endif // _WIN32 } class FileStream::FileStreamPrivate { public: FileStreamPrivate(const FileName &fileName) : file(InvalidFileHandle) , name(fileName) , readOnly(true) { } FileHandle file; FileNameHandle name; bool readOnly; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// FileStream::FileStream(FileName fileName, bool openReadOnly) : d(new FileStreamPrivate(fileName)) { // First try with read / write mode, if that fails, fall back to read only. if(!openReadOnly) d->file = openFile(fileName, false); if(d->file != InvalidFileHandle) d->readOnly = false; else d->file = openFile(fileName, true); if(d->file == InvalidFileHandle) { # ifdef _WIN32 debug("Could not open file " + fileName.toString()); # else debug("Could not open file " + String(static_cast<const char *>(d->name))); # endif } } FileStream::~FileStream() { if(isOpen()) closeFile(d->file); delete d; } FileName FileStream::name() const { return d->name; } ByteVector FileStream::readBlock(ulong length) { if(!isOpen()) { debug("File::readBlock() -- invalid file."); return ByteVector::null; } if(length == 0) return ByteVector::null; const ulong streamLength = static_cast<ulong>(FileStream::length()); if(length > bufferSize() && length > streamLength) length = streamLength; ByteVector buffer(static_cast<uint>(length)); const size_t count = readFile(d->file, buffer); buffer.resize(static_cast<uint>(count)); return buffer; } void FileStream::writeBlock(const ByteVector &data) { if(!isOpen()) { debug("File::writeBlock() -- invalid file."); return; } if(readOnly()) { debug("File::writeBlock() -- read only file."); return; } writeFile(d->file, data); } void FileStream::insert(const ByteVector &data, ulong start, ulong replace) { if(!isOpen()) { debug("File::insert() -- invalid file."); return; } if(readOnly()) { debug("File::insert() -- read only 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 = data; ByteVector aboutToOverwrite(static_cast<uint>(bufferLength)); while(true) { // Seek to the current read position and read the data that we're about // to overwrite. Appropriately increment the readPosition. seek(readPosition); const size_t bytesRead = readFile(d->file, aboutToOverwrite); 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(bytesRead < bufferLength) clear(); // Seek to the write position and write our buffer. Increment the // writePosition. seek(writePosition); writeBlock(buffer); // We hit the end of the file. if(bytesRead == 0) break; writePosition += buffer.size(); // Make the current buffer the data that we read in the beginning. buffer = aboutToOverwrite; } } void FileStream::removeBlock(ulong start, ulong length) { if(!isOpen()) { debug("File::removeBlock() -- invalid file."); return; } ulong bufferLength = bufferSize(); long readPosition = start + length; long writePosition = start; ByteVector buffer(static_cast<uint>(bufferLength)); for(size_t bytesRead = -1; bytesRead != 0;) { seek(readPosition); bytesRead = readFile(d->file, buffer); 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 < buffer.size()) { clear(); buffer.resize(bytesRead); } seek(writePosition); writeFile(d->file, buffer); writePosition += bytesRead; } truncate(writePosition); } bool FileStream::readOnly() const { return d->readOnly; } bool FileStream::isOpen() const { return (d->file != InvalidFileHandle); } void FileStream::seek(long offset, Position p) { if(!isOpen()) { debug("File::seek() -- invalid file."); return; } #ifdef _WIN32 DWORD whence; switch(p) { case Beginning: whence = FILE_BEGIN; break; case Current: whence = FILE_CURRENT; break; case End: whence = FILE_END; break; default: debug("FileStream::seek() -- Invalid Position value."); return; } SetFilePointer(d->file, offset, NULL, whence); if(GetLastError() != NO_ERROR) { debug("File::seek() -- Failed to set the file pointer."); } #else int whence; switch(p) { case Beginning: whence = SEEK_SET; break; case Current: whence = SEEK_CUR; break; case End: whence = SEEK_END; break; default: debug("FileStream::seek() -- Invalid Position value."); return; } fseek(d->file, offset, whence); #endif } void FileStream::clear() { #ifdef _WIN32 // NOP #else clearerr(d->file); #endif } long FileStream::tell() const { #ifdef _WIN32 const DWORD position = SetFilePointer(d->file, 0, NULL, FILE_CURRENT); if(GetLastError() == NO_ERROR) { return static_cast<long>(position); } else { debug("File::tell() -- Failed to get the file pointer."); return 0; } #else return ftell(d->file); #endif } long FileStream::length() { if(!isOpen()) { debug("File::length() -- invalid file."); return 0; } #ifdef _WIN32 const DWORD fileSize = GetFileSize(d->file, NULL); if(GetLastError() == NO_ERROR) { return static_cast<ulong>(fileSize); } else { debug("File::length() -- Failed to get the file size."); return 0; } #else const long curpos = tell(); seek(0, End); const long endpos = tell(); seek(curpos, Beginning); return endpos; #endif } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// void FileStream::truncate(long length) { #ifdef _WIN32 const long currentPos = tell(); seek(length); SetEndOfFile(d->file); if(GetLastError() != NO_ERROR) { debug("File::truncate() -- Failed to truncate the file."); } seek(currentPos); #else const int error = ftruncate(fileno(d->file), length); if(error != 0) { debug("FileStream::truncate() -- Coundn't truncate the file."); } #endif } TagLib::uint FileStream::bufferSize() { return BufferSize; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tfilestream.h�����������������������������������������������������������0000664�0000000�0000000�00000011675�12225024651�0020414�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_FILESTREAM_H #define TAGLIB_FILESTREAM_H #include "taglib_export.h" #include "taglib.h" #include "tbytevector.h" #include "tiostream.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 TAGLIB_EXPORT FileStream : public IOStream { public: /*! * Construct a File object and opens the \a file. \a file should be a * be a C-string in the local file system encoding. */ FileStream(FileName file, bool openReadOnly = false); /*! * Destroys this FileStream instance. */ virtual ~FileStream(); /*! * Returns the file name in the local file system encoding. */ FileName name() const; /*! * 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); /*! * 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; /*! * 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 within the file. */ long tell() const; /*! * Returns the length of the file. */ long length(); /*! * Truncates the file to a \a length. */ void truncate(long length); protected: /*! * Returns the buffer size that is used for internal buffering. */ static uint bufferSize(); private: class FileStreamPrivate; FileStreamPrivate *d; }; } #endif �������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tiostream.cpp�����������������������������������������������������������0000664�0000000�0000000�00000010342�12225024651�0020425�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Lukas Lalinsky email : lalinsky@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "tiostream.h" using namespace TagLib; #ifdef _WIN32 # include "tstring.h" # include "tdebug.h" # include <windows.h> namespace { // Check if the running system has CreateFileW() function. // Windows9x systems don't have CreateFileW() or can't accept Unicode file names. bool supportsUnicode() { const FARPROC p = GetProcAddress(GetModuleHandleA("kernel32"), "CreateFileW"); return (p != NULL); } // Indicates whether the system supports Unicode file names. const bool SystemSupportsUnicode = supportsUnicode(); // Converts a UTF-16 string into a local encoding. // This function should only be used in Windows9x systems which don't support // Unicode file names. std::string unicodeToAnsi(const wchar_t *wstr) { if(SystemSupportsUnicode) { debug("unicodeToAnsi() - Should not be used on WinNT systems."); } const int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); if(len == 0) return std::string(); std::string str(len, '\0'); WideCharToMultiByte(CP_ACP, 0, wstr, -1, &str[0], len, NULL, NULL); return str; } } // If WinNT, stores a Unicode string into m_wname directly. // If Win9x, converts and stores it into m_name to avoid calling Unicode version functions. FileName::FileName(const wchar_t *name) : m_name (SystemSupportsUnicode ? "" : unicodeToAnsi(name)) , m_wname(SystemSupportsUnicode ? name : L"") { } FileName::FileName(const char *name) : m_name(name) { } FileName::FileName(const FileName &name) : m_name (name.m_name) , m_wname(name.m_wname) { } FileName::operator const wchar_t *() const { return m_wname.c_str(); } FileName::operator const char *() const { return m_name.c_str(); } const std::wstring &FileName::wstr() const { return m_wname; } const std::string &FileName::str() const { return m_name; } String FileName::toString() const { if(!m_wname.empty()) { return String(m_wname); } else if(!m_name.empty()) { const int len = MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, NULL, 0); if(len == 0) return String::null; std::vector<wchar_t> buf(len); MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, &buf[0], len); return String(&buf[0]); } else { return String::null; } } #endif // _WIN32 //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// IOStream::IOStream() { } IOStream::~IOStream() { } void IOStream::clear() { } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tiostream.h�������������������������������������������������������������0000664�0000000�0000000�00000012311�12225024651�0020070�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Lukas Lalinsky email : lalinsky@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_IOSTREAM_H #define TAGLIB_IOSTREAM_H #include "taglib_export.h" #include "taglib.h" #include "tbytevector.h" namespace TagLib { #ifdef _WIN32 class TAGLIB_EXPORT FileName { public: FileName(const wchar_t *name); FileName(const char *name); FileName(const FileName &name); operator const wchar_t *() const; operator const char *() const; const std::wstring &wstr() const; const std::string &str() const; String toString() const; private: const std::string m_name; const std::wstring m_wname; }; #else typedef const char *FileName; #endif //! An abstract class that provides operations on a sequence of bytes class TAGLIB_EXPORT IOStream { 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 }; IOStream(); /*! * Destroys this IOStream instance. */ virtual ~IOStream(); /*! * Returns the stream name in the local file system encoding. */ virtual FileName name() const = 0; /*! * Reads a block of size \a length at the current get pointer. */ virtual ByteVector readBlock(ulong length) = 0; /*! * 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[]. */ virtual void writeBlock(const ByteVector &data) = 0; /*! * 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. */ virtual void insert(const ByteVector &data, ulong start = 0, ulong replace = 0) = 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. */ virtual void removeBlock(ulong start = 0, ulong length = 0) = 0; /*! * Returns true if the file is read only (or if the file can not be opened). */ virtual bool readOnly() const = 0; /*! * Since the file can currently only be opened as an argument to the * constructor (sort-of by design), this returns if that open succeeded. */ virtual bool isOpen() const = 0; /*! * Move the I/O pointer to \a offset in the stream from position \a p. This * defaults to seeking from the beginning of the stream. * * \see Position */ virtual void seek(long offset, Position p = Beginning) = 0; /*! * Reset the end-of-stream and error flags on the stream. */ virtual void clear(); /*! * Returns the current offset within the stream. */ virtual long tell() const = 0; /*! * Returns the length of the stream. */ virtual long length() = 0; /*! * Truncates the stream to a \a length. */ virtual void truncate(long length) = 0; private: IOStream(const IOStream &); IOStream &operator=(const IOStream &); }; } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tlist.h�����������������������������������������������������������������0000664�0000000�0000000�00000016664�12225024651�0017237�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_LIST_H #define TAGLIB_LIST_H #include "taglib.h" #include <list> 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<int> 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 T> class List { public: #ifndef DO_NOT_DOCUMENT typedef typename std::list<T>::iterator Iterator; typedef typename std::list<T>::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<T> &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. */ Iterator 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. */ List<T> &sortedInsert(const T &value, bool unique = false); /*! * Appends \a item to the end of the list and returns a reference to the * list. */ List<T> &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<T> &append(const List<T> &l); /*! * Prepends \a item to the beginning list and returns a reference to the * list. */ List<T> &prepend(const T &item); /*! * Prepends all of the items in \a l to the beginning list and returns a * reference to the list. */ List<T> &prepend(const List<T> &l); /*! * Clears the list. If auto deletion is enabled and this list contains a * pointer type the members are also deleted. * * \see setAutoDelete() */ List<T> &clear(); /*! * Returns the number of elements in the list. */ uint size() const; bool isEmpty() const; /*! * Find the first occurrence of \a value. */ Iterator find(const T &value); /*! * Find the first occurrence 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. */ Iterator 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<T> &operator=(const List<T> &l); /*! * Compares this list with \a l and returns true if all of the elements are * the same. */ bool operator==(const List<T> &l) const; /*! * Compares this list with \a l and returns true if the lists differ. */ bool operator!=(const List<T> &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 TP> class ListPrivate; ListPrivate<T> *d; #endif }; } // Since GCC doesn't support the "export" keyword, we have to include the // implementation. #include "tlist.tcc" #endif ����������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tlist.tcc���������������������������������������������������������������0000664�0000000�0000000�00000016257�12225024651�0017557�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <algorithm> #include "trefcounter.h" namespace TagLib { //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// // The functionality of List<T>::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. // BIC change to RefCounter class ListPrivateBase : public RefCounterOld { public: ListPrivateBase() : autoDelete(false) {} bool autoDelete; }; // A generic implementation template <class T> template <class TP> class List<T>::ListPrivate : public ListPrivateBase { public: ListPrivate() : ListPrivateBase() {} ListPrivate(const std::list<TP> &l) : ListPrivateBase(), list(l) {} void clear() { list.clear(); } std::list<TP> list; }; // A partial specialization for all pointer types that implements the // setAutoDelete() functionality. template <class T> template <class TP> class List<T>::ListPrivate<TP *> : public ListPrivateBase { public: ListPrivate() : ListPrivateBase() {} ListPrivate(const std::list<TP *> &l) : ListPrivateBase(), list(l) {} ~ListPrivate() { clear(); } void clear() { if(autoDelete) { typename std::list<TP *>::const_iterator it = list.begin(); for(; it != list.end(); ++it) delete *it; } list.clear(); } std::list<TP *> list; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// template <class T> List<T>::List() { d = new ListPrivate<T>; } template <class T> List<T>::List(const List<T> &l) : d(l.d) { d->ref(); } template <class T> List<T>::~List() { if(d->deref()) delete d; } template <class T> typename List<T>::Iterator List<T>::begin() { detach(); return d->list.begin(); } template <class T> typename List<T>::ConstIterator List<T>::begin() const { return d->list.begin(); } template <class T> typename List<T>::Iterator List<T>::end() { detach(); return d->list.end(); } template <class T> typename List<T>::ConstIterator List<T>::end() const { return d->list.end(); } template <class T> typename List<T>::Iterator List<T>::insert(Iterator it, const T &item) { detach(); return d->list.insert(it, item); } template <class T> List<T> &List<T>::sortedInsert(const T &value, bool unique) { detach(); Iterator it = begin(); while(it != end() && *it < value) ++it; if(unique && it != end() && *it == value) return *this; insert(it, value); return *this; } template <class T> List<T> &List<T>::append(const T &item) { detach(); d->list.push_back(item); return *this; } template <class T> List<T> &List<T>::append(const List<T> &l) { detach(); d->list.insert(d->list.end(), l.begin(), l.end()); return *this; } template <class T> List<T> &List<T>::prepend(const T &item) { detach(); d->list.push_front(item); return *this; } template <class T> List<T> &List<T>::prepend(const List<T> &l) { detach(); d->list.insert(d->list.begin(), l.begin(), l.end()); return *this; } template <class T> List<T> &List<T>::clear() { detach(); d->clear(); return *this; } template <class T> TagLib::uint List<T>::size() const { return d->list.size(); } template <class T> bool List<T>::isEmpty() const { return d->list.empty(); } template <class T> typename List<T>::Iterator List<T>::find(const T &value) { return std::find(d->list.begin(), d->list.end(), value); } template <class T> typename List<T>::ConstIterator List<T>::find(const T &value) const { return std::find(d->list.begin(), d->list.end(), value); } template <class T> bool List<T>::contains(const T &value) const { return std::find(d->list.begin(), d->list.end(), value) != d->list.end(); } template <class T> typename List<T>::Iterator List<T>::erase(Iterator it) { return d->list.erase(it); } template <class T> const T &List<T>::front() const { return d->list.front(); } template <class T> T &List<T>::front() { detach(); return d->list.front(); } template <class T> const T &List<T>::back() const { return d->list.back(); } template <class T> void List<T>::setAutoDelete(bool autoDelete) { d->autoDelete = autoDelete; } template <class T> T &List<T>::back() { detach(); return d->list.back(); } template <class T> T &List<T>::operator[](uint i) { Iterator it = d->list.begin(); for(uint j = 0; j < i; j++) ++it; return *it; } template <class T> const T &List<T>::operator[](uint i) const { ConstIterator it = d->list.begin(); for(uint j = 0; j < i; j++) ++it; return *it; } template <class T> List<T> &List<T>::operator=(const List<T> &l) { if(&l == this) return *this; if(d->deref()) delete d; d = l.d; d->ref(); return *this; } template <class T> bool List<T>::operator==(const List<T> &l) const { return d->list == l.d->list; } template <class T> bool List<T>::operator!=(const List<T> &l) const { return d->list != l.d->list; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// template <class T> void List<T>::detach() { if(d->count() > 1) { d->deref(); d = new ListPrivate<T>(d->list); } } } // namespace TagLib �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tmap.h������������������������������������������������������������������0000664�0000000�0000000�00000014171�12225024651�0017030�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_MAP_H #define TAGLIB_MAP_H #include <map> #include "taglib.h" 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 Key, class T> class Map { public: #ifndef DO_NOT_DOCUMENT #ifdef WANT_CLASS_INSTANTIATION_OF_MAP // Some STL implementations get snippy over the use of the // class keyword to distinguish different templates; Sun Studio // in particular finds multiple specializations in certain rare // cases and complains about that. GCC doesn't seem to mind, // and uses the typedefs further below without the class keyword. // Not all the specializations of Map can use the class keyword // (when T is not actually a class type), so don't apply this // generally. typedef typename std::map<class Key, class T>::iterator Iterator; typedef typename std::map<class Key, class T>::const_iterator ConstIterator; #else typedef typename std::map<Key, T>::iterator Iterator; typedef typename std::map<Key, T>::const_iterator ConstIterator; #endif #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<Key, T> &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. */ Map<Key, T> &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. */ Map<Key, T> &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 occurrence of \a key. */ Iterator find(const Key &key); /*! * Find the first occurrence 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. */ Map<Key, T> &erase(Iterator it); /*! * Erase the item with \a key from the list. */ Map<Key, T> &erase(const Key &key); /*! * 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<Key, T> &operator=(const Map<Key, T> &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 KeyP, class TP> class MapPrivate; MapPrivate<Key, T> *d; #endif }; } // Since GCC doesn't support the "export" keyword, we have to include the // implementation. #include "tmap.tcc" #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tmap.tcc����������������������������������������������������������������0000664�0000000�0000000�00000012000�12225024651�0017337�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "trefcounter.h" namespace TagLib { //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// // BIC change to RefCounter template <class Key, class T> template <class KeyP, class TP> class Map<Key, T>::MapPrivate : public RefCounterOld { public: MapPrivate() : RefCounterOld() {} #ifdef WANT_CLASS_INSTANTIATION_OF_MAP MapPrivate(const std::map<class KeyP, class TP>& m) : RefCounterOld(), map(m) {} std::map<class KeyP, class TP> map; #else MapPrivate(const std::map<KeyP, TP>& m) : RefCounterOld(), map(m) {} std::map<KeyP, TP> map; #endif }; template <class Key, class T> Map<Key, T>::Map() { d = new MapPrivate<Key, T>; } template <class Key, class T> Map<Key, T>::Map(const Map<Key, T> &m) : d(m.d) { d->ref(); } template <class Key, class T> Map<Key, T>::~Map() { if(d->deref()) delete(d); } template <class Key, class T> typename Map<Key, T>::Iterator Map<Key, T>::begin() { detach(); return d->map.begin(); } template <class Key, class T> typename Map<Key, T>::ConstIterator Map<Key, T>::begin() const { return d->map.begin(); } template <class Key, class T> typename Map<Key, T>::Iterator Map<Key, T>::end() { detach(); return d->map.end(); } template <class Key, class T> typename Map<Key, T>::ConstIterator Map<Key, T>::end() const { return d->map.end(); } template <class Key, class T> Map<Key, T> &Map<Key, T>::insert(const Key &key, const T &value) { detach(); d->map[key] = value; return *this; } template <class Key, class T> Map<Key, T> &Map<Key, T>::clear() { detach(); d->map.clear(); return *this; } template <class Key, class T> bool Map<Key, T>::isEmpty() const { return d->map.empty(); } template <class Key, class T> typename Map<Key, T>::Iterator Map<Key, T>::find(const Key &key) { detach(); return d->map.find(key); } template <class Key, class T> typename Map<Key,T>::ConstIterator Map<Key, T>::find(const Key &key) const { return d->map.find(key); } template <class Key, class T> bool Map<Key, T>::contains(const Key &key) const { return d->map.find(key) != d->map.end(); } template <class Key, class T> Map<Key, T> &Map<Key,T>::erase(Iterator it) { detach(); d->map.erase(it); return *this; } template <class Key, class T> Map<Key, T> &Map<Key,T>::erase(const Key &key) { detach(); Iterator it = d->map.find(key); if(it != d->map.end()) d->map.erase(it); return *this; } template <class Key, class T> TagLib::uint Map<Key, T>::size() const { return d->map.size(); } template <class Key, class T> const T &Map<Key, T>::operator[](const Key &key) const { return d->map[key]; } template <class Key, class T> T &Map<Key, T>::operator[](const Key &key) { detach(); return d->map[key]; } template <class Key, class T> Map<Key, T> &Map<Key, T>::operator=(const Map<Key, T> &m) { if(&m == this) return *this; if(d->deref()) delete(d); d = m.d; d->ref(); return *this; } //////////////////////////////////////////////////////////////////////////////// // protected members //////////////////////////////////////////////////////////////////////////////// template <class Key, class T> void Map<Key, T>::detach() { if(d->count() > 1) { d->deref(); d = new MapPrivate<Key, T>(d->map); } } } // namespace TagLib taglib-1.9.1/taglib/toolkit/tpropertymap.cpp��������������������������������������������������������0000664�0000000�0000000�00000012061�12225024651�0021164�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Michael Helmling email : helmling@mathematik.uni-kl.de ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "tpropertymap.h" using namespace TagLib; PropertyMap::PropertyMap() : SimplePropertyMap() { } PropertyMap::PropertyMap(const PropertyMap &m) : SimplePropertyMap(m), unsupported(m.unsupported) { } PropertyMap::PropertyMap(const SimplePropertyMap &m) { for(SimplePropertyMap::ConstIterator it = m.begin(); it != m.end(); ++it){ String key = it->first.upper(); if(!key.isNull()) insert(it->first, it->second); else unsupported.append(it->first); } } PropertyMap::~PropertyMap() { } bool PropertyMap::insert(const String &key, const StringList &values) { String realKey = key.upper(); Iterator result = SimplePropertyMap::find(realKey); if(result == end()) SimplePropertyMap::insert(realKey, values); else SimplePropertyMap::operator[](realKey).append(values); return true; } bool PropertyMap::replace(const String &key, const StringList &values) { String realKey = key.upper(); SimplePropertyMap::erase(realKey); SimplePropertyMap::insert(realKey, values); return true; } PropertyMap::Iterator PropertyMap::find(const String &key) { return SimplePropertyMap::find(key.upper()); } PropertyMap::ConstIterator PropertyMap::find(const String &key) const { return SimplePropertyMap::find(key.upper()); } bool PropertyMap::contains(const String &key) const { return SimplePropertyMap::contains(key.upper()); } bool PropertyMap::contains(const PropertyMap &other) const { for(ConstIterator it = other.begin(); it != other.end(); ++it) { if(!SimplePropertyMap::contains(it->first)) return false; if ((*this)[it->first] != it->second) return false; } return true; } PropertyMap &PropertyMap::erase(const String &key) { SimplePropertyMap::erase(key.upper()); return *this; } PropertyMap &PropertyMap::erase(const PropertyMap &other) { for(ConstIterator it = other.begin(); it != other.end(); ++it) erase(it->first); return *this; } PropertyMap &PropertyMap::merge(const PropertyMap &other) { for(PropertyMap::ConstIterator it = other.begin(); it != other.end(); ++it) insert(it->first, it->second); unsupported.append(other.unsupported); return *this; } const StringList &PropertyMap::operator[](const String &key) const { return SimplePropertyMap::operator[](key.upper()); } StringList &PropertyMap::operator[](const String &key) { return SimplePropertyMap::operator[](key.upper()); } bool PropertyMap::operator==(const PropertyMap &other) const { for(ConstIterator it = other.begin(); it != other.end(); ++it) { ConstIterator thisFind = find(it->first); if( thisFind == end() || (thisFind->second != it->second) ) return false; } for(ConstIterator it = begin(); it != end(); ++it) { ConstIterator otherFind = other.find(it->first); if( otherFind == other.end() || (otherFind->second != it->second) ) return false; } return unsupported == other.unsupported; } bool PropertyMap::operator!=(const PropertyMap &other) const { return !(*this == other); } String PropertyMap::toString() const { String ret = ""; for(ConstIterator it = begin(); it != end(); ++it) ret += it->first+"="+it->second.toString(", ") + "\n"; if(!unsupported.isEmpty()) ret += "Unsupported Data: " + unsupported.toString(", ") + "\n"; return ret; } void PropertyMap::removeEmpty() { StringList emptyKeys; for(Iterator it = begin(); it != end(); ++it) if(it->second.isEmpty()) emptyKeys.append(it->first); for(StringList::Iterator emptyIt = emptyKeys.begin(); emptyIt != emptyKeys.end(); emptyIt++ ) erase(*emptyIt); } StringList &PropertyMap::unsupportedData() { return unsupported; } const StringList &PropertyMap::unsupportedData() const { return unsupported; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tpropertymap.h����������������������������������������������������������0000664�0000000�0000000�00000015604�12225024651�0020637�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2012 by Michael Helmling email : helmling@mathematik.uni-kl.de ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef PROPERTYMAP_H_ #define PROPERTYMAP_H_ #include "tmap.h" #include "tstringlist.h" namespace TagLib { typedef Map<String,StringList> SimplePropertyMap; //! A map for format-independent <key,valuelist> tag representations. /*! * This map implements a generic representation of textual audio metadata * ("tags") realized as pairs of a case-insensitive key * and a nonempty list of corresponding values, each value being an an arbitrary * unicode String. * * Note that most metadata formats pose additional conditions on the tag keys. The * most popular ones (Vorbis, APE, ID3v2) should support all ASCII only words of * length between 2 and 16. * * This class can contain any tags, but here is a list of "well-known" tags that * you might want to use: * * Basic tags: * * - TITLE * - ALBUM * - ARTIST * - ALBUMARTIST * - SUBTITLE * - TRACKNUMBER * - DISCNUMBER * - DATE * - ORIGINALDATE * - GENRE * - COMMENT * * Sort names: * * - TITLESORT * - ALBUMSORT * - ARTISTSORT * - ALBUMARTISTSORT * * Credits: * * - COMPOSER * - LYRICIST * - CONDUCTOR * - REMIXER * - PERFORMER:<XXXX> * * Other tags: * * - ISRC * - ASIN * - BPM * - COPYRIGHT * - ENCODEDBY * - MOOD * - COMMENT * - MEDIA * - LABEL * - CATALOGNUMBER * - BARCODE * * MusicBrainz identifiers: * * - MUSICBRAINZ_TRACKID * - MUSICBRAINZ_ALBUMID * - MUSICBRAINZ_RELEASEGROUPID * - MUSICBRAINZ_WORKID * - MUSICBRAINZ_ARTISTID * - MUSICBRAINZ_ALBUMARTISTID * - ACOUSTID_ID * - ACOUSTID_FINGERPRINT * - MUSICIP_PUID * */ class TAGLIB_EXPORT PropertyMap: public SimplePropertyMap { public: typedef SimplePropertyMap::Iterator Iterator; typedef SimplePropertyMap::ConstIterator ConstIterator; PropertyMap(); PropertyMap(const PropertyMap &m); /*! * Creates a PropertyMap initialized from a SimplePropertyMap. Copies all * entries from \a m that have valid keys. * Invalid keys will be appended to the unsupportedData() list. */ PropertyMap(const SimplePropertyMap &m); virtual ~PropertyMap(); /*! * Inserts \a values under \a key in the map. If \a key already exists, * then \values will be appended to the existing StringList. * The returned value indicates success, i.e. whether \a key is a * valid key. */ bool insert(const String &key, const StringList &values); /*! * Replaces any existing values for \a key with the given \a values, * and simply insert them if \a key did not exist before. * The returned value indicates success, i.e. whether \a key is a * valid key. */ bool replace(const String &key, const StringList &values); /*! * Find the first occurrence of \a key. */ Iterator find(const String &key); /*! * Find the first occurrence of \a key. */ ConstIterator find(const String &key) const; /*! * Returns true if the map contains values for \a key. */ bool contains(const String &key) const; /*! * Returns true if this map contains all keys of \a other * and the values coincide for that keys. Does not take * the unsupportedData list into account. */ bool contains(const PropertyMap &other) const; /*! * Erase the \a key and its values from the map. */ PropertyMap &erase(const String &key); /*! * Erases from this map all keys that appear in \a other. */ PropertyMap &erase(const PropertyMap &other); /*! * Merge the contents of \a other into this PropertyMap. * If a key is contained in both maps, the values of the second * are appended to that of the first. * The unsupportedData() lists are concatenated as well. */ PropertyMap &merge(const PropertyMap &other); /*! * Returns a reference to the value associated with \a key. * * \note: If \a key is not contained in the map, an empty * StringList is returned without error. */ const StringList &operator[](const String &key) const; /*! * Returns a reference to the value associated with \a key. * * \note: If \a key is not contained in the map, an empty * StringList is returned. You can also directly add entries * by using this function as an lvalue. */ StringList &operator[](const String &key); /*! * Returns true if and only if \other has the same contents as this map. */ bool operator==(const PropertyMap &other) const; /*! * Returns false if and only \other has the same contents as this map. */ bool operator!=(const PropertyMap &other) const; /*! * If a PropertyMap is read from a File object using File::properties(), * the StringList returned from this function will represent metadata * that could not be parsed into the PropertyMap representation. This could * be e.g. binary data, unknown ID3 frames, etc. * You can remove items from the returned list, which tells TagLib to remove * those unsupported elements if you call File::setProperties() with the * same PropertyMap as argument. */ StringList &unsupportedData(); const StringList &unsupportedData() const; /*! * Removes all entries which have an empty value list. */ void removeEmpty(); String toString() const; private: StringList unsupported; }; } #endif /* PROPERTYMAP_H_ */ ����������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/trefcounter.cpp���������������������������������������������������������0000664�0000000�0000000�00000007046�12225024651�0020765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2013 by Tsuda Kageyu email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include "trefcounter.h" #if defined(HAVE_STD_ATOMIC) # include <atomic> # define ATOMIC_INT std::atomic<unsigned int> # define ATOMIC_INC(x) x.fetch_add(1) # define ATOMIC_DEC(x) (x.fetch_sub(1) - 1) #elif defined(HAVE_BOOST_ATOMIC) # include <boost/atomic.hpp> # define ATOMIC_INT boost::atomic<unsigned int> # define ATOMIC_INC(x) x.fetch_add(1) # define ATOMIC_DEC(x) (x.fetch_sub(1) - 1) #elif defined(HAVE_GCC_ATOMIC) # define ATOMIC_INT int # define ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) # define ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) #elif defined(HAVE_WIN_ATOMIC) # if !defined(NOMINMAX) # define NOMINMAX # endif # include <windows.h> # define ATOMIC_INT long # define ATOMIC_INC(x) InterlockedIncrement(&x) # define ATOMIC_DEC(x) InterlockedDecrement(&x) #elif defined(HAVE_MAC_ATOMIC) # include <libkern/OSAtomic.h> # define ATOMIC_INT int32_t # define ATOMIC_INC(x) OSAtomicIncrement32Barrier(&x) # define ATOMIC_DEC(x) OSAtomicDecrement32Barrier(&x) #elif defined(HAVE_IA64_ATOMIC) # include <ia64intrin.h> # define ATOMIC_INT int # define ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) # define ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) #else # define ATOMIC_INT int # define ATOMIC_INC(x) (++x) # define ATOMIC_DEC(x) (--x) #endif namespace TagLib { class RefCounter::RefCounterPrivate { public: RefCounterPrivate() : refCount(1) {} void ref() { ATOMIC_INC(refCount); } bool deref() { return (ATOMIC_DEC(refCount) == 0); } int count() const { return refCount; } volatile ATOMIC_INT refCount; }; RefCounter::RefCounter() : d(new RefCounterPrivate()) { } RefCounter::~RefCounter() { delete d; } void RefCounter::ref() { d->ref(); } bool RefCounter::deref() { return d->deref(); } int RefCounter::count() const { return d->count(); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/trefcounter.h�����������������������������������������������������������0000664�0000000�0000000�00000007615�12225024651�0020434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2013 by Tsuda Kageyu email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_REFCOUNTER_H #define TAGLIB_REFCOUNTER_H #include "taglib_export.h" #include "taglib.h" #ifdef __APPLE__ # include <libkern/OSAtomic.h> # define TAGLIB_ATOMIC_MAC #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # define NOMINMAX # include <windows.h> # define TAGLIB_ATOMIC_WIN #elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ && !defined(__INTEL_COMPILER) # define TAGLIB_ATOMIC_GCC #elif defined(__ia64) && defined(__INTEL_COMPILER) # include <ia64intrin.h> # define TAGLIB_ATOMIC_GCC #endif #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 <b>is not</b> part of the TagLib public API! */ namespace TagLib { class TAGLIB_EXPORT RefCounter { public: RefCounter(); virtual ~RefCounter(); void ref(); bool deref(); int count() const; private: class RefCounterPrivate; RefCounterPrivate *d; }; // BIC this old class is needed by tlist.tcc and tmap.tcc class RefCounterOld { public: RefCounterOld() : refCount(1) {} #ifdef TAGLIB_ATOMIC_MAC void ref() { OSAtomicIncrement32Barrier(const_cast<int32_t*>(&refCount)); } bool deref() { return ! OSAtomicDecrement32Barrier(const_cast<int32_t*>(&refCount)); } int32_t count() { return refCount; } private: volatile int32_t refCount; #elif defined(TAGLIB_ATOMIC_WIN) void ref() { InterlockedIncrement(&refCount); } bool deref() { return ! InterlockedDecrement(&refCount); } long count() { return refCount; } private: volatile long refCount; #elif defined(TAGLIB_ATOMIC_GCC) void ref() { __sync_add_and_fetch(&refCount, 1); } bool deref() { return ! __sync_sub_and_fetch(&refCount, 1); } int count() { return refCount; } private: volatile int refCount; #else void ref() { refCount++; } bool deref() { return ! --refCount; } int count() { return refCount; } private: uint refCount; #endif }; } #endif // DO_NOT_DOCUMENT #endif �������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tstring.cpp�������������������������������������������������������������0000664�0000000�0000000�00000044710�12225024651�0020116�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ // This class assumes that std::basic_string<T> has a contiguous and null-terminated buffer. #ifdef HAVE_CONFIG_H #include <config.h> #endif #include "tstring.h" #include "tdebug.h" #include "tstringlist.h" #include "trefcounter.h" #include "tutils.h" #include <iostream> #include <cstdio> #include <cstring> #ifdef HAVE_STD_CODECVT # include <codecvt> #else # include "unicode.h" #endif namespace { inline unsigned short combine(unsigned char c1, unsigned char c2) { return (c1 << 8) | c2; } void UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength) { #ifdef HAVE_STD_CODECVT typedef std::codecvt_utf8_utf16<wchar_t> utf8_utf16_t; using namespace TagLib; const wchar_t *srcBegin = src; const wchar_t *srcEnd = srcBegin + srcLength; char *dstBegin = dst; char *dstEnd = dstBegin + dstLength; std::mbstate_t st; const wchar_t *source; char *target; memset(&st, 0, sizeof(st)); std::codecvt_base::result result = utf8_utf16_t().out( st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); if(result != utf8_utf16_t::ok) { debug("String::copyFromUTF8() - Unicode conversion error."); } #else using namespace Unicode; using namespace TagLib; const Unicode::UTF16 *srcBegin = src; const Unicode::UTF16 *srcEnd = srcBegin + srcLength; Unicode::UTF8 *dstBegin = reinterpret_cast<Unicode::UTF8*>(dst); Unicode::UTF8 *dstEnd = dstBegin + dstLength; Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); if(result != Unicode::conversionOK) { debug("String::to8Bit() - Unicode conversion error."); } #endif } void UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength) { #ifdef HAVE_STD_CODECVT typedef std::codecvt_utf8_utf16<wchar_t> utf8_utf16_t; using namespace TagLib; const char *srcBegin = src; const char *srcEnd = srcBegin + srcLength; wchar_t *dstBegin = dst; wchar_t *dstEnd = dstBegin + dstLength; std::mbstate_t st; const char *source; wchar_t *target; memset(&st, 0, sizeof(st)); std::codecvt_base::result result = utf8_utf16_t().in( st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); if(result != utf8_utf16_t::ok) { debug("String::copyFromUTF8() - Unicode conversion error."); } #else using namespace Unicode; using namespace TagLib; const Unicode::UTF8 *srcBegin = reinterpret_cast<const Unicode::UTF8*>(src); const Unicode::UTF8 *srcEnd = srcBegin + srcLength; Unicode::UTF16 *dstBegin = dst; Unicode::UTF16 *dstEnd = dstBegin + dstLength; Unicode::ConversionResult result = Unicode::ConvertUTF8toUTF16( &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); if(result != Unicode::conversionOK) { debug("String::copyFromUTF8() - Unicode conversion error."); } #endif } } namespace TagLib { class String::StringPrivate : public RefCounter { public: StringPrivate() : RefCounter() { } StringPrivate(const wstring &s) : RefCounter() , data(s) { } StringPrivate(uint n, wchar_t c) : RefCounter() , data(static_cast<size_t>(n), c) { } /*! * Stores string in UTF-16. The byte order depends on the CPU endian. */ TagLib::wstring data; /*! * This is only used to hold the the most recent value of toCString(). */ std::string 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 == Latin1) copyFromLatin1(&s[0], s.length()); else if(t == String::UTF8) copyFromUTF8(&s[0], s.length()); else { debug("String::String() -- A std::string should not contain UTF16."); } } String::String(const wstring &s, Type t) : d(new StringPrivate()) { if(t == UTF16 || t == UTF16BE || t == UTF16LE) copyFromUTF16(s.c_str(), s.length(), t); else { debug("String::String() -- A TagLib::wstring should not contain Latin1 or UTF-8."); } } String::String(const wchar_t *s, Type t) : d(new StringPrivate()) { if(t == UTF16 || t == UTF16BE || t == UTF16LE) copyFromUTF16(s, ::wcslen(s), t); else { debug("String::String() -- A const wchar_t * should not contain Latin1 or UTF-8."); } } String::String(const char *s, Type t) : d(new StringPrivate()) { if(t == Latin1) copyFromLatin1(s, ::strlen(s)); else if(t == String::UTF8) copyFromUTF8(s, ::strlen(s)); else { debug("String::String() -- A const char * should not contain UTF16."); } } String::String(wchar_t c, Type t) : d(new StringPrivate()) { if(t == UTF16 || t == UTF16BE || t == UTF16LE) copyFromUTF16(&c, 1, t); else { debug("String::String() -- A const wchar_t should not contain Latin1 or UTF-8."); } } String::String(char c, Type t) : d(new StringPrivate(1, static_cast<uchar>(c))) { if(t != Latin1 && t != UTF8) { debug("String::String() -- A char should not contain UTF16."); } } String::String(const ByteVector &v, Type t) : d(new StringPrivate()) { if(v.isEmpty()) return; if(t == Latin1) copyFromLatin1(v.data(), v.size()); else if(t == UTF8) copyFromUTF8(v.data(), v.size()); else copyFromUTF16(v.data(), v.size(), t); // If we hit a null in the ByteVector, shrink the string again. d->data.resize(::wcslen(d->data.c_str())); } //////////////////////////////////////////////////////////////////////////////// String::~String() { if(d->deref()) delete d; } std::string String::to8Bit(bool unicode) const { std::string s; if(!unicode) { s.resize(d->data.size()); std::string::iterator targetIt = s.begin(); for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { *targetIt = static_cast<char>(*it); ++targetIt; } } else { s.resize(d->data.size() * 4 + 1); UTF16toUTF8(&d->data[0], d->data.size(), &s[0], s.size()); s.resize(::strlen(s.c_str())); } return s; } TagLib::wstring String::toWString() const { return d->data; } const char *String::toCString(bool unicode) const { d->cstring = to8Bit(unicode); return d->cstring.c_str(); } const wchar_t *String::toCWString() const { return d->data.c_str(); } 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 { return d->data.find(s.d->data, offset); } int String::rfind(const String &s, int offset) const { return d->data.rfind(s.d->data, offset); } StringList String::split(const String &separator) const { StringList list; for(int index = 0;;) { int sep = find(separator, index); if(sep < 0) { list.append(substr(index, size() - index)); break; } else { list.append(substr(index, sep - index)); index = sep + separator.size(); } } return list; } bool String::startsWith(const String &s) const { if(s.length() > length()) return false; return substr(0, s.length()) == s; } String String::substr(uint position, uint n) const { return String(d->data.substr(position, n)); } 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(); } TagLib::uint String::length() const { return size(); } bool String::isEmpty() const { return d->data.size() == 0; } bool String::isNull() const { return d == null.d; } ByteVector String::data(Type t) const { switch(t) { case Latin1: { ByteVector v(size(), 0); char *p = v.data(); for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) *p++ = static_cast<char>(*it); return v; } case UTF8: { ByteVector v(size() * 4 + 1, 0); UTF16toUTF8(&d->data[0], d->data.size(), v.data(), v.size()); v.resize(::strlen(v.data())); return v; } case UTF16: { ByteVector v(2 + size() * 2, 0); char *p = v.data(); // Assume that if we're doing UTF16 and not UTF16BE that we want little // endian encoding. (Byte Order Mark) *p++ = '\xff'; *p++ = '\xfe'; for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { *p++ = static_cast<char>(*it & 0xff); *p++ = static_cast<char>(*it >> 8); } return v; } case UTF16BE: { ByteVector v(size() * 2, 0); char *p = v.data(); for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { *p++ = static_cast<char>(*it >> 8); *p++ = static_cast<char>(*it & 0xff); } return v; } case UTF16LE: { ByteVector v(size() * 2, 0); char *p = v.data(); for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { *p++ = static_cast<char>(*it & 0xff); *p++ = static_cast<char>(*it >> 8); } return v; } default: { debug("String::data() - Invalid Type value."); return ByteVector(); } } } int String::toInt() const { return toInt(0); } int String::toInt(bool *ok) const { int value = 0; uint size = d->data.size(); bool negative = size > 0 && d->data[0] == '-'; uint start = negative ? 1 : 0; uint i = start; for(; i < size && d->data[i] >= '0' && d->data[i] <= '9'; i++) value = value * 10 + (d->data[i] - '0'); if(negative) value = value * -1; if(ok) *ok = (size > start && i == size); return value; } String String::stripWhiteSpace() const { wstring::const_iterator begin = d->data.begin(); wstring::const_iterator end = d->data.end(); while(begin != end && (*begin == '\t' || *begin == '\n' || *begin == '\f' || *begin == '\r' || *begin == ' ')) { ++begin; } if(begin == end) return null; // There must be at least one non-whitespace character 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)); } bool String::isLatin1() const { for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { if(*it >= 256) return false; } return true; } bool String::isAscii() const { for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { if(*it >= 128) return false; } return true; } String String::number(int n) // static { static const size_t BufferSize = 11; // Sufficient to store "-214748364". static const char *Format = "%d"; char buffer[BufferSize]; int length; #if defined(HAVE_SNPRINTF) length = snprintf(buffer, BufferSize, Format, n); #elif defined(HAVE_SPRINTF_S) length = sprintf_s(buffer, Format, n); #else length = sprintf(buffer, Format, n); #endif if(length > 0) return String(buffer); else return String::null; } TagLib::wchar &String::operator[](int i) { detach(); 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; } bool String::operator!=(const String &s) const { return !operator==(s); } 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) { detach(); 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; copyFromLatin1(s.c_str(), s.length()); 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(1, static_cast<uchar>(c)); return *this; } String &String::operator=(wchar_t c) { if(d->deref()) delete d; d = new StringPrivate(1, c); return *this; } String &String::operator=(const char *s) { if(d->deref()) delete d; d = new StringPrivate; copyFromLatin1(s, ::strlen(s)); return *this; } String &String::operator=(const ByteVector &v) { if(d->deref()) delete d; d = new StringPrivate; copyFromLatin1(v.data(), v.size()); // If we hit a null in the ByteVector, shrink the string again. d->data.resize(::wcslen(d->data.c_str())); 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::copyFromLatin1(const char *s, size_t length) { d->data.resize(length); for(size_t i = 0; i < length; ++i) d->data[i] = static_cast<uchar>(s[i]); } void String::copyFromUTF8(const char *s, size_t length) { d->data.resize(length); UTF8toUTF16(s, length, &d->data[0], d->data.size()); d->data.resize(::wcslen(d->data.c_str())); } void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) { bool swap; if(t == UTF16) { if(length >= 1 && s[0] == 0xfeff) swap = false; // Same as CPU endian. No need to swap bytes. else if(length >= 1 && s[0] == 0xfffe) swap = true; // Not same as CPU endian. Need to swap bytes. else { debug("String::copyFromUTF16() - Invalid UTF16 string."); return; } s++; length--; } else swap = (t != WCharByteOrder); d->data.resize(length); memcpy(&d->data[0], s, length * sizeof(wchar_t)); if(swap) { for(size_t i = 0; i < length; ++i) d->data[i] = Utils::byteSwap(static_cast<ushort>(s[i])); } } void String::copyFromUTF16(const char *s, size_t length, Type t) { bool swap; if(t == UTF16) { if(length < 2) { debug("String::copyFromUTF16() - Invalid UTF16 string."); return; } // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. ushort bom; ::memcpy(&bom, s, 2); if(bom == 0xfeff) swap = false; // Same as CPU endian. No need to swap bytes. else if(bom == 0xfffe) swap = true; // Not same as CPU endian. Need to swap bytes. else { debug("String::copyFromUTF16() - Invalid UTF16 string."); return; } s += 2; length -= 2; } else swap = (t != WCharByteOrder); d->data.resize(length / 2); for(size_t i = 0; i < length / 2; ++i) { d->data[i] = swap ? combine(*s, *(s + 1)) : combine(*(s + 1), *s); s += 2; } } const String::Type String::WCharByteOrder = (Utils::SystemByteOrder == Utils::BigEndian) ? String::UTF16BE : String::UTF16LE; } //////////////////////////////////////////////////////////////////////////////// // related functions //////////////////////////////////////////////////////////////////////////////// const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2) { TagLib::String s(s1); s.append(s2); return s; } const TagLib::String operator+(const char *s1, const TagLib::String &s2) { TagLib::String s(s1); s.append(s2); return s; } const TagLib::String operator+(const TagLib::String &s1, const char *s2) { TagLib::String s(s1); s.append(s2); return s; } std::ostream &operator<<(std::ostream &s, const TagLib::String &str) { s << str.to8Bit(); return s; } ��������������������������������������������������������taglib-1.9.1/taglib/toolkit/tstring.h���������������������������������������������������������������0000664�0000000�0000000�00000037275�12225024651�0017573�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_STRING_H #define TAGLIB_STRING_H #include "taglib_export.h" #include "taglib.h" #include "tbytevector.h" #include <string> #include <iostream> /*! * \relates TagLib::String * * Converts a QString to a TagLib::String without a requirement to link to Qt. * * \note consider conversion via usual char-by-char for loop to avoid UTF16->UTF8->UTF16 * conversion happening in the background */ #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. * * \note consider conversion via usual char-by-char for loop to avoid UTF16->UTF8->UTF16 * conversion happening in the background * */ #define TStringToQString(s) QString::fromUtf8(s.toCString(true)) namespace TagLib { class StringList; //! 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 <i>implementation detail</i> this of * course could change. Strings are stored internally as UTF-16(without BOM/ * CPU byte order) * * 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 TAGLIB_EXPORT String { public: #ifndef DO_NOT_DOCUMENT typedef std::basic_string<wchar>::iterator Iterator; typedef std::basic_string<wchar>::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 <i>Latin1</i> encoding. 8 bit characters. */ Latin1 = 0, /*! * UTF16 with a <i>byte order mark</i>. 16 bit characters. */ UTF16 = 1, /*! * UTF16 <i>big endian</i>. 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, /*! * UTF16 <i>little endian</i>. 16 bit characters. */ UTF16LE = 4 }; /*! * 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 = WCharByteOrder); /*! * Makes a deep copy of the data in \a s. */ String(const wchar_t *s, Type t = WCharByteOrder); /*! * 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(); /*! * Returns a deep copy of this String as an std::string. The returned string * is encoded in UTF8 if \a unicode is true, otherwise Latin1. * * \see toCString() */ std::string to8Bit(bool unicode = false) const; /*! * Returns a deep copy of this String as a wstring. The returned string is * encoded in UTF-16 (without BOM/CPU byte order). * * \see toCWString() */ wstring toWString() const; /*! * Creates and returns a standard C-style (null-terminated) version of this * String. The returned string is encoded in UTF8 if \a unicode is true, * otherwise Latin1. * * The returned string is still owned by this String and should not be deleted * by the user. * * The returned pointer remains valid until this String instance is destroyed * or toCString() is called again. * * \warning This however has the side effect that the returned string will remain * in memory <b>in addition to</b> other memory that is consumed by this * String instance. So, this method should not be used on large strings or * where memory is critical. Consider using to8Bit() instead to avoid it. * * \see to8Bit() */ const char *toCString(bool unicode = false) const; /*! * Returns a standard C-style (null-terminated) wide character version of * this String. The returned string is encoded in UTF-16 (without BOM/CPU byte * order). * * The returned string is still owned by this String and should not be deleted * by the user. * * The returned pointer remains valid until this String instance is destroyed * or any other method of this String is called. * * /note This returns a pointer to the String's internal data without any * conversions. * * \see toWString() */ const wchar_t *toCWString() 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 occurrence 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; /*! * Finds the last occurrence of pattern \a s in this string, searched backwards, * either from the end of the string or starting from \a offset. If the pattern * is not found, -1 is returned. */ int rfind(const String &s, int offset = -1) const; /*! * Splits the string on each occurrence of \a separator. */ StringList split(const String &separator = " ") const; /*! * Returns true if the strings starts with the substring \a s. */ bool startsWith(const String &s) 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 the length of the string. Equivalent to size(). */ uint length() 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. * * Returns the integer if the conversion was successful or 0 if the * string does not represent a number. */ // BIC: merge with the method below int toInt() const; /*! * Convert the string to an integer. * * If the conversion was successfull, it sets the value of \a *ok to * true and returns the integer. Otherwise it sets \a *ok to false * and the result is undefined. */ int toInt(bool *ok) const; /*! * Returns a string with the leading and trailing whitespace stripped. */ String stripWhiteSpace() const; /*! * Returns true if the file only uses characters required by Latin1. */ bool isLatin1() const; /*! * Returns true if the file only uses characters required by (7-bit) ASCII. */ bool isAscii() 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; /*! * Compares each character of the String with each character of \a s and * returns false 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: /*! * Converts a \e Latin-1 string into \e UTF-16(without BOM/CPU byte order) * and copies it to the internal buffer. */ void copyFromLatin1(const char *s, size_t length); /*! * Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order) * and copies it to the internal buffer. */ void copyFromUTF8(const char *s, size_t length); /*! * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. */ void copyFromUTF16(const wchar_t *s, size_t length, Type t); /*! * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. */ void copyFromUTF16(const char *s, size_t length, Type t); /*! * Indicates which byte order of UTF-16 is used to store strings internally. * * \note \e String::UTF16BE or \e String::UTF16LE */ static const Type WCharByteOrder; class StringPrivate; StringPrivate *d; }; } /*! * \relates TagLib::String * * Concatenates \a s1 and \a s2 and returns the result as a string. */ TAGLIB_EXPORT const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2); /*! * \relates TagLib::String * * Concatenates \a s1 and \a s2 and returns the result as a string. */ TAGLIB_EXPORT const TagLib::String operator+(const char *s1, const TagLib::String &s2); /*! * \relates TagLib::String * * Concatenates \a s1 and \a s2 and returns the result as a string. */ TAGLIB_EXPORT const TagLib::String operator+(const TagLib::String &s1, const char *s2); /*! * \relates TagLib::String * * Send the string to an output stream. */ TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const TagLib::String &str); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tstringlist.cpp���������������������������������������������������������0000664�0000000�0000000�00000007163�12225024651�0021013�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include "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<String>() { } StringList::StringList(const StringList &l) : List<String>(l) { } StringList::StringList(const String &s) : List<String>() { append(s); } StringList::StringList(const ByteVectorList &bl, String::Type t) : List<String>() { 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(); ConstIterator itEnd = end(); while(it != itEnd) { s += *it; it++; if(it != itEnd) s += separator; } return s; } StringList &StringList::append(const String &s) { List<String>::append(s); return *this; } StringList &StringList::append(const StringList &l) { List<String>::append(l); return *this; } //////////////////////////////////////////////////////////////////////////////// // related functions //////////////////////////////////////////////////////////////////////////////// std::ostream &operator<<(std::ostream &s, const StringList &l) { s << l.toString(); return s; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tstringlist.h�����������������������������������������������������������0000664�0000000�0000000�00000007410�12225024651�0020453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_STRINGLIST_H #define TAGLIB_STRINGLIST_H #include "tstring.h" #include "tlist.h" #include "tbytevectorlist.h" #include "taglib_export.h" #include <iostream> namespace TagLib { //! A list of strings /*! * This is a spcialization of the List class with some members convention for * string operations. */ class TAGLIB_EXPORT StringList : public List<String> { 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 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/tutils.h����������������������������������������������������������������0000664�0000000�0000000�00000010674�12225024651�0017417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2013 by Tsuda Kageyu email : tsuda.kageyu@gmail.com ***************************************************************************/ /*************************************************************************** * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_TUTILS_H #define TAGLIB_TUTILS_H // THIS FILE IS NOT A PART OF THE TAGLIB API #ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header #ifdef HAVE_CONFIG_H #include <config.h> #endif #if defined(HAVE_MSC_BYTESWAP) # include <stdlib.h> #elif defined(HAVE_GLIBC_BYTESWAP) # include <byteswap.h> #elif defined(HAVE_MAC_BYTESWAP) # include <libkern/OSByteOrder.h> #elif defined(HAVE_OPENBSD_BYTESWAP) # include <sys/endian.h> #endif namespace TagLib { namespace Utils { inline ushort byteSwap(ushort x) { #if defined(HAVE_GCC_BYTESWAP_16) return __builtin_bswap16(x); #elif defined(HAVE_MSC_BYTESWAP) return _byteswap_ushort(x); #elif defined(HAVE_GLIBC_BYTESWAP) return __bswap_16(x); #elif defined(HAVE_MAC_BYTESWAP) return OSSwapInt16(x); #elif defined(HAVE_OPENBSD_BYTESWAP) return swap16(x); #else return ((x >> 8) & 0xff) | ((x & 0xff) << 8); #endif } inline uint byteSwap(uint x) { #if defined(HAVE_GCC_BYTESWAP_32) return __builtin_bswap32(x); #elif defined(HAVE_MSC_BYTESWAP) return _byteswap_ulong(x); #elif defined(HAVE_GLIBC_BYTESWAP) return __bswap_32(x); #elif defined(HAVE_MAC_BYTESWAP) return OSSwapInt32(x); #elif defined(HAVE_OPENBSD_BYTESWAP) return swap32(x); #else return ((x & 0xff000000u) >> 24) | ((x & 0x00ff0000u) >> 8) | ((x & 0x0000ff00u) << 8) | ((x & 0x000000ffu) << 24); #endif } inline ulonglong byteSwap(ulonglong x) { #if defined(HAVE_GCC_BYTESWAP_64) return __builtin_bswap64(x); #elif defined(HAVE_MSC_BYTESWAP) return _byteswap_uint64(x); #elif defined(HAVE_GLIBC_BYTESWAP) return __bswap_64(x); #elif defined(HAVE_MAC_BYTESWAP) return OSSwapInt64(x); #elif defined(HAVE_OPENBSD_BYTESWAP) return swap64(x); #else return ((x & 0xff00000000000000ull) >> 56) | ((x & 0x00ff000000000000ull) >> 40) | ((x & 0x0000ff0000000000ull) >> 24) | ((x & 0x000000ff00000000ull) >> 8) | ((x & 0x00000000ff000000ull) << 8) | ((x & 0x0000000000ff0000ull) << 24) | ((x & 0x000000000000ff00ull) << 40) | ((x & 0x00000000000000ffull) << 56); #endif } enum ByteOrder { LittleEndian, BigEndian }; #ifdef SYSTEM_BYTEORDER # if SYSTEM_BYTEORDER == 1 const ByteOrder SystemByteOrder = LittleEndian; # else const ByteOrder SystemByteOrder = BigEndian; # endif #else inline ByteOrder systemByteOrder() { union { int i; char c; } u; u.i = 1; if(u.c == 1) return LittleEndian; else return BigEndian; } const ByteOrder SystemByteOrder = systemByteOrder(); #endif } } #endif #endif ��������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/unicode.cpp�������������������������������������������������������������0000664�0000000�0000000�00000025510�12225024651�0020047�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/******************************************************************************* * * * 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 <wheeler@kde.org> 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 <stdio.h> #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 = (UTF8)(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++ = (UTF16)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++ = (UTF16)((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. --------------------------------------------------------------------- */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/toolkit/unicode.h���������������������������������������������������������������0000664�0000000�0000000�00000014225�12225024651�0017515�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#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 <wheeler@kde.org> 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 functions 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: <F4 90 80 80>, <C0 80>, or <A0> 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. ------------------------------------------------------------------------ */ // Workaround for when MSVC doesn't have wchar_t as a built-in type. #if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) # include <wchar.h> #endif /* 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 wchar_t UTF16; /* TagLib assumes that wchar_t is sufficient for UTF-16. */ 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 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/trueaudio/����������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0016226�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/trueaudio/trueaudiofile.cpp�����������������������������������������������������0000664�0000000�0000000�00000021035�12225024651�0021574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tstring.h> #include <tdebug.h> #include <tagunion.h> #include <tstringlist.h> #include <tpropertymap.h> #include "trueaudiofile.h" #include "id3v1tag.h" #include "id3v2tag.h" #include "id3v2header.h" using namespace TagLib; namespace { enum { TrueAudioID3v2Index = 0, TrueAudioID3v1Index = 1 }; } class TrueAudio::File::FilePrivate { public: FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : ID3v2FrameFactory(frameFactory), ID3v2Location(-1), ID3v2OriginalSize(0), ID3v1Location(-1), properties(0), hasID3v1(false), hasID3v2(false) {} ~FilePrivate() { delete properties; } const ID3v2::FrameFactory *ID3v2FrameFactory; long ID3v2Location; uint ID3v2OriginalSize; long ID3v1Location; TagUnion tag; Properties *properties; // These indicate whether the file *on disk* has these tags, not if // this data structure does. This is used in computing offsets. bool hasID3v1; bool hasID3v2; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// TrueAudio::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } TrueAudio::File::File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate(frameFactory); if(isOpen()) read(readProperties, propertiesStyle); } TrueAudio::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } TrueAudio::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate(frameFactory); if(isOpen()) read(readProperties, propertiesStyle); } TrueAudio::File::~File() { delete d; } TagLib::Tag *TrueAudio::File::tag() const { return &d->tag; } PropertyMap TrueAudio::File::properties() const { // once Tag::properties() is virtual, this case distinction could actually be done // within TagUnion. if(d->hasID3v2) return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, false)->properties(); if(d->hasID3v1) return d->tag.access<ID3v1::Tag>(TrueAudioID3v1Index, false)->properties(); return PropertyMap(); } void TrueAudio::File::removeUnsupportedProperties(const StringList &unsupported) { if(d->hasID3v2) d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, false)->removeUnsupportedProperties(unsupported); } PropertyMap TrueAudio::File::setProperties(const PropertyMap &properties) { if(d->hasID3v1) d->tag.access<ID3v1::Tag>(TrueAudioID3v1Index, false)->setProperties(properties); return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, true)->setProperties(properties); } TrueAudio::Properties *TrueAudio::File::audioProperties() const { return d->properties; } void TrueAudio::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) { d->ID3v2FrameFactory = factory; } bool TrueAudio::File::save() { if(readOnly()) { debug("TrueAudio::File::save() -- File is read only."); return false; } // Update ID3v2 tag if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { if(!d->hasID3v2) { d->ID3v2Location = 0; d->ID3v2OriginalSize = 0; } ByteVector data = ID3v2Tag()->render(); insert(data, d->ID3v2Location, d->ID3v2OriginalSize); d->ID3v1Location -= d->ID3v2OriginalSize - data.size(); d->ID3v2OriginalSize = data.size(); d->hasID3v2 = true; } else if(d->hasID3v2) { removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); d->ID3v1Location -= d->ID3v2OriginalSize; d->ID3v2Location = -1; d->ID3v2OriginalSize = 0; d->hasID3v2 = false; } // Update ID3v1 tag if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { if(!d->hasID3v1) { seek(0, End); d->ID3v1Location = tell(); } else seek(d->ID3v1Location); writeBlock(ID3v1Tag()->render()); d->hasID3v1 = true; } else if(d->hasID3v1) { removeBlock(d->ID3v1Location, 128); d->ID3v1Location = -1; d->hasID3v1 = false; } return true; } ID3v1::Tag *TrueAudio::File::ID3v1Tag(bool create) { return d->tag.access<ID3v1::Tag>(TrueAudioID3v1Index, create); } ID3v2::Tag *TrueAudio::File::ID3v2Tag(bool create) { return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, create); } void TrueAudio::File::strip(int tags) { if(tags & ID3v1) { d->tag.set(TrueAudioID3v1Index, 0); ID3v2Tag(true); } if(tags & ID3v2) { d->tag.set(TrueAudioID3v2Index, 0); if(!ID3v1Tag()) ID3v2Tag(true); } } bool TrueAudio::File::hasID3v1Tag() const { return d->hasID3v1; } bool TrueAudio::File::hasID3v2Tag() const { return d->hasID3v2; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void TrueAudio::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) { // Look for an ID3v2 tag d->ID3v2Location = findID3v2(); if(d->ID3v2Location >= 0) { d->tag.set(TrueAudioID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); if(ID3v2Tag()->header()->tagSize() <= 0) d->tag.set(TrueAudioID3v2Index, 0); else d->hasID3v2 = true; } // Look for an ID3v1 tag d->ID3v1Location = findID3v1(); if(d->ID3v1Location >= 0) { d->tag.set(TrueAudioID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); d->hasID3v1 = true; } if(!d->hasID3v1) ID3v2Tag(true); // Look for TrueAudio metadata if(readProperties) { if(d->ID3v2Location >= 0) { seek(d->ID3v2Location + d->ID3v2OriginalSize); d->properties = new Properties(readBlock(TrueAudio::HeaderSize), length() - d->ID3v2OriginalSize); } else { seek(0); d->properties = new Properties(readBlock(TrueAudio::HeaderSize), length()); } } } long TrueAudio::File::findID3v1() { if(!isValid()) return -1; seek(-128, End); long p = tell(); if(readBlock(3) == ID3v1::Tag::fileIdentifier()) return p; return -1; } long TrueAudio::File::findID3v2() { if(!isValid()) return -1; seek(0); if(readBlock(3) == ID3v2::Header::fileIdentifier()) return 0; return -1; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/trueaudio/trueaudiofile.h�������������������������������������������������������0000664�0000000�0000000�00000021771�12225024651�0021250�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_TRUEAUDIOFILE_H #define TAGLIB_TRUEAUDIOFILE_H #include "tfile.h" #include "trueaudioproperties.h" namespace TagLib { class Tag; namespace ID3v2 { class Tag; class FrameFactory; } namespace ID3v1 { class Tag; } //! An implementation of TrueAudio metadata /*! * This is implementation of TrueAudio metadata. * * This supports ID3v1 and ID3v2 tags as well as reading stream * properties from the file. */ namespace TrueAudio { //! An implementation of TagLib::File with TrueAudio specific methods /*! * This implements and provides an interface for TrueAudio 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 TrueAudio files. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * This set of flags is used for various operations and is suitable for * being OR-ed together. */ enum TagTypes { //! Empty set. Matches no tag types. NoTags = 0x0000, //! Matches ID3v1 tags. ID3v1 = 0x0001, //! Matches ID3v2 tags. ID3v2 = 0x0002, //! Matches all tag types. AllTags = 0xffff }; /*! * Constructs a TrueAudio file from \a file. If \a readProperties is true * the file's audio properties will also be read. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs a TrueAudio file from \a file. If \a readProperties is true * the file's audio properties will also be read. * * If this file contains and ID3v2 tag the frames will be created using * \a frameFactory. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(FileName file, ID3v2::FrameFactory *frameFactory, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs a TrueAudio file from \a stream. If \a readProperties is true * the file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs a TrueAudio file from \a stream. If \a readProperties is true * the file's audio properties will also be read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. * * If this file contains and ID3v2 tag the frames will be created using * \a frameFactory. * * \note In the current implementation, \a propertiesStyle is ignored. */ File(IOStream *stream, 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. */ virtual TagLib::Tag *tag() const; /*! * Implements the unified property interface -- export function. * If the file contains both ID3v1 and v2 tags, only ID3v2 will be * converted to the PropertyMap. */ PropertyMap properties() const; /*! * Implements the unified property interface -- import function. * Creates in ID3v2 tag if necessary. If an ID3v1 tag exists, it will * be updated as well, within the limitations of ID3v1. */ PropertyMap setProperties(const PropertyMap &); void removeUnsupportedProperties(const StringList &properties); /*! * Returns the TrueAudio::Properties for this file. If no audio properties * were read then this will return a null pointer. */ virtual Properties *audioProperties() const; /*! * Set the ID3v2::FrameFactory to something other than the default. * * \see ID3v2FrameFactory */ void setID3v2FrameFactory(const ID3v2::FrameFactory *factory); /*! * Saves the file. */ virtual bool save(); /*! * Returns a pointer to the ID3v1 tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file * on disk actually has an ID3v1 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v1Tag() */ ID3v1::Tag *ID3v1Tag(bool create = false); /*! * Returns a pointer to the ID3v2 tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file * on disk actually has an ID3v2 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v2Tag() */ ID3v2::Tag *ID3v2Tag(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 strip(int tags = AllTags); /*! * Returns whether or not the file on disk actually has an ID3v1 tag. * * \see ID3v1Tag() */ bool hasID3v1Tag() const; /*! * Returns whether or not the file on disk actually has an ID3v2 tag. * * \see ID3v2Tag() */ bool hasID3v2Tag() const; private: File(const File &); File &operator=(const File &); void read(bool readProperties, Properties::ReadStyle propertiesStyle); void scan(); long findID3v1(); long findID3v2(); class FilePrivate; FilePrivate *d; }; } } #endif �������taglib-1.9.1/taglib/trueaudio/trueaudioproperties.cpp�����������������������������������������������0000664�0000000�0000000�00000010514�12225024651�0023051�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include <bitset> #include "trueaudioproperties.h" #include "trueaudiofile.h" using namespace TagLib; class TrueAudio::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), bitsPerSample(0), sampleFrames(0) {} ByteVector data; long streamLength; ReadStyle style; int version; int length; int bitrate; int sampleRate; int channels; int bitsPerSample; uint sampleFrames; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// TrueAudio::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(data, streamLength, style); read(); } TrueAudio::Properties::~Properties() { delete d; } int TrueAudio::Properties::length() const { return d->length; } int TrueAudio::Properties::bitrate() const { return d->bitrate; } int TrueAudio::Properties::sampleRate() const { return d->sampleRate; } int TrueAudio::Properties::bitsPerSample() const { return d->bitsPerSample; } int TrueAudio::Properties::channels() const { return d->channels; } TagLib::uint TrueAudio::Properties::sampleFrames() const { return d->sampleFrames; } int TrueAudio::Properties::ttaVersion() const { return d->version; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void TrueAudio::Properties::read() { if(!d->data.startsWith("TTA")) return; int pos = 3; d->version = d->data[pos] - '0'; pos += 1; // According to http://en.true-audio.com/TTA_Lossless_Audio_Codec_-_Format_Description // TTA2 headers are in development, and have a different format if(1 == d->version) { // Skip the audio format pos += 2; d->channels = d->data.toShort(pos, false); pos += 2; d->bitsPerSample = d->data.toShort(pos, false); pos += 2; d->sampleRate = d->data.toUInt(pos, false); pos += 4; d->sampleFrames = d->data.toUInt(pos, false); d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/trueaudio/trueaudioproperties.h�������������������������������������������������0000664�0000000�0000000�00000006420�12225024651�0022517�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_TRUEAUDIOPROPERTIES_H #define TAGLIB_TRUEAUDIOPROPERTIES_H #include "audioproperties.h" namespace TagLib { namespace TrueAudio { class File; static const uint HeaderSize = 18; //! An implementation of audio property reading for TrueAudio /*! * This reads the data from an TrueAudio stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of TrueAudio::Properties with the data read from the * ByteVector \a data. */ Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); /*! * Destroys this TrueAudio::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; virtual int sampleRate() const; virtual int channels() const; /*! * Returns number of bits per sample. */ int bitsPerSample() const; /*! * Returns the total number of sample frames */ uint sampleFrames() const; /*! * Returns the major version number. */ int ttaVersion() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/wavpack/������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015661�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/wavpack/wavpackfile.cpp���������������������������������������������������������0000664�0000000�0000000�00000016756�12225024651�0020700�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tbytevector.h> #include <tstring.h> #include <tdebug.h> #include <tagunion.h> #include <tpropertymap.h> #include "wavpackfile.h" #include "id3v1tag.h" #include "id3v2header.h" #include "apetag.h" #include "apefooter.h" using namespace TagLib; namespace { enum { WavAPEIndex, WavID3v1Index }; } class WavPack::File::FilePrivate { public: FilePrivate() : APELocation(-1), APESize(0), ID3v1Location(-1), properties(0), hasAPE(false), hasID3v1(false) {} ~FilePrivate() { delete properties; } long APELocation; uint APESize; long ID3v1Location; TagUnion tag; Properties *properties; // 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; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// WavPack::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(file) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } WavPack::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) : TagLib::File(stream) { d = new FilePrivate; if(isOpen()) read(readProperties, propertiesStyle); } WavPack::File::~File() { delete d; } TagLib::Tag *WavPack::File::tag() const { return &d->tag; } PropertyMap WavPack::File::properties() const { if(d->hasAPE) return d->tag.access<APE::Tag>(WavAPEIndex, false)->properties(); if(d->hasID3v1) return d->tag.access<ID3v1::Tag>(WavID3v1Index, false)->properties(); return PropertyMap(); } void WavPack::File::removeUnsupportedProperties(const StringList &unsupported) { if(d->hasAPE) d->tag.access<APE::Tag>(WavAPEIndex, false)->removeUnsupportedProperties(unsupported); } PropertyMap WavPack::File::setProperties(const PropertyMap &properties) { if(d->hasID3v1) d->tag.access<ID3v1::Tag>(WavID3v1Index, false)->setProperties(properties); return d->tag.access<APE::Tag>(WavAPEIndex, true)->setProperties(properties); } WavPack::Properties *WavPack::File::audioProperties() const { return d->properties; } bool WavPack::File::save() { if(readOnly()) { debug("WavPack::File::save() -- File is read only."); return false; } // Update ID3v1 tag if(ID3v1Tag()) { if(d->hasID3v1) { seek(d->ID3v1Location); writeBlock(ID3v1Tag()->render()); } else { seek(0, End); d->ID3v1Location = tell(); writeBlock(ID3v1Tag()->render()); d->hasID3v1 = true; } } else { if(d->hasID3v1) { removeBlock(d->ID3v1Location, 128); d->hasID3v1 = false; if(d->hasAPE) { if(d->APELocation > d->ID3v1Location) d->APELocation -= 128; } } } // Update APE tag if(APETag()) { if(d->hasAPE) insert(APETag()->render(), d->APELocation, d->APESize); else { if(d->hasID3v1) { insert(APETag()->render(), d->ID3v1Location, 0); d->APESize = APETag()->footer()->completeTagSize(); d->hasAPE = true; d->APELocation = d->ID3v1Location; d->ID3v1Location += d->APESize; } else { seek(0, End); d->APELocation = tell(); writeBlock(APETag()->render()); d->APESize = APETag()->footer()->completeTagSize(); d->hasAPE = true; } } } else { if(d->hasAPE) { removeBlock(d->APELocation, d->APESize); d->hasAPE = false; if(d->hasID3v1) { if(d->ID3v1Location > d->APELocation) { d->ID3v1Location -= d->APESize; } } } } return true; } ID3v1::Tag *WavPack::File::ID3v1Tag(bool create) { return d->tag.access<ID3v1::Tag>(WavID3v1Index, create); } APE::Tag *WavPack::File::APETag(bool create) { return d->tag.access<APE::Tag>(WavAPEIndex, create); } void WavPack::File::strip(int tags) { if(tags & ID3v1) { d->tag.set(WavID3v1Index, 0); APETag(true); } if(tags & APE) { d->tag.set(WavAPEIndex, 0); if(!ID3v1Tag()) APETag(true); } } bool WavPack::File::hasID3v1Tag() const { return d->hasID3v1; } bool WavPack::File::hasAPETag() const { return d->hasAPE; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void WavPack::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) { // Look for an ID3v1 tag d->ID3v1Location = findID3v1(); if(d->ID3v1Location >= 0) { d->tag.set(WavID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); d->hasID3v1 = true; } // Look for an APE tag d->APELocation = findAPE(); if(d->APELocation >= 0) { d->tag.set(WavAPEIndex, new APE::Tag(this, d->APELocation)); d->APESize = APETag()->footer()->completeTagSize(); d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; d->hasAPE = true; } if(!d->hasID3v1) APETag(true); // Look for WavPack audio properties if(readProperties) { seek(0); d->properties = new Properties(this, length() - d->APESize); } } long WavPack::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 WavPack::File::findID3v1() { if(!isValid()) return -1; seek(-128, End); long p = tell(); if(readBlock(3) == ID3v1::Tag::fileIdentifier()) return p; return -1; } ������������������taglib-1.9.1/taglib/wavpack/wavpackfile.h�����������������������������������������������������������0000664�0000000�0000000�00000017203�12225024651�0020331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_WVFILE_H #define TAGLIB_WVFILE_H #include "tfile.h" #include "taglib_export.h" #include "wavpackproperties.h" namespace TagLib { class Tag; namespace ID3v1 { class Tag; } namespace APE { class Tag; } //! An implementation of WavPack metadata /*! * This is implementation of WavPack metadata. * * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream * properties from the file. */ namespace WavPack { //! An implementation of TagLib::File with WavPack specific methods /*! * This implements and provides an interface for WavPack 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 WavPack files. */ class TAGLIB_EXPORT File : public TagLib::File { public: /*! * This set of flags is used for various operations and is suitable for * being OR-ed together. */ enum TagTypes { //! Empty set. Matches no tag types. NoTags = 0x0000, //! Matches ID3v1 tags. ID3v1 = 0x0001, //! Matches APE tags. APE = 0x0002, //! Matches all tag types. AllTags = 0xffff }; /*! * Constructs a WavPack file from \a file. If \a readProperties is true the * file's audio properties will also be read using \a propertiesStyle. If * false, \a propertiesStyle is ignored */ File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); /*! * Constructs an WavPack 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 TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. */ File(IOStream *stream, 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; /*! * Implements the unified property interface -- export function. * If the file contains both an APE and an ID3v1 tag, only APE * will be converted to the PropertyMap. */ PropertyMap properties() const; void removeUnsupportedProperties(const StringList &properties); /*! * Implements the unified property interface -- import function. * Creates an APE tag if it does not exists and calls setProperties() on * that. Any existing ID3v1 tag will be updated as well. */ PropertyMap setProperties(const PropertyMap&); /*! * 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 may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file * on disk actually has an ID3v1 tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasID3v1Tag() */ ID3v1::Tag *ID3v1Tag(bool create = false); /*! * Returns a pointer to the APE tag of the file. * * If \a create is false (the default) this may 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 and returns a valid pointer. * * \note This may return a valid pointer regardless of whether or not the * file on disk has an APE tag. Use hasAPETag() to check if the file * on disk actually has an APE tag. * * \note The Tag <b>is still</b> owned by the MPEG::File and should not be * deleted by the user. It will be deleted when the file (object) is * destroyed. * * \see hasAPETag() */ 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 strip(int tags = AllTags); /*! * Returns whether or not the file on disk actually has an ID3v1 tag. * * \see ID3v1Tag() */ bool hasID3v1Tag() const; /*! * Returns whether or not the file on disk actually has an APE tag. * * \see APETag() */ bool hasAPETag() const; private: File(const File &); File &operator=(const File &); void read(bool readProperties, Properties::ReadStyle propertiesStyle); void scan(); long findID3v1(); long findAPE(); class FilePrivate; FilePrivate *d; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/wavpack/wavpackproperties.cpp���������������������������������������������������0000664�0000000�0000000�00000013500�12225024651�0022135�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #include <tstring.h> #include <tdebug.h> #include "wavpackproperties.h" #include "wavpackfile.h" using namespace TagLib; class WavPack::Properties::PropertiesPrivate { public: PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) : data(d), streamLength(length), style(s), length(0), bitrate(0), sampleRate(0), channels(0), version(0), bitsPerSample(0), sampleFrames(0), file(0) {} ByteVector data; long streamLength; ReadStyle style; int length; int bitrate; int sampleRate; int channels; int version; int bitsPerSample; uint sampleFrames; File *file; }; //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// WavPack::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate(data, streamLength, style); read(); } WavPack::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style) { ByteVector data = file->readBlock(32); d = new PropertiesPrivate(data, streamLength, style); d->file = file; read(); } WavPack::Properties::~Properties() { delete d; } int WavPack::Properties::length() const { return d->length; } int WavPack::Properties::bitrate() const { return d->bitrate; } int WavPack::Properties::sampleRate() const { return d->sampleRate; } int WavPack::Properties::channels() const { return d->channels; } int WavPack::Properties::version() const { return d->version; } int WavPack::Properties::bitsPerSample() const { return d->bitsPerSample; } TagLib::uint WavPack::Properties::sampleFrames() const { return d->sampleFrames; } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// static const unsigned int sample_rates[] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000, 0 }; #define BYTES_STORED 3 #define MONO_FLAG 4 #define SHIFT_LSB 13 #define SHIFT_MASK (0x1fL << SHIFT_LSB) #define SRATE_LSB 23 #define SRATE_MASK (0xfL << SRATE_LSB) #define MIN_STREAM_VERS 0x402 #define MAX_STREAM_VERS 0x410 #define FINAL_BLOCK 0x1000 void WavPack::Properties::read() { if(!d->data.startsWith("wvpk")) return; d->version = d->data.toShort(8, false); if(d->version < MIN_STREAM_VERS || d->version > MAX_STREAM_VERS) return; const unsigned int flags = d->data.toUInt(24, false); d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 - ((flags & SHIFT_MASK) >> SHIFT_LSB); d->sampleRate = sample_rates[(flags & SRATE_MASK) >> SRATE_LSB]; d->channels = (flags & MONO_FLAG) ? 1 : 2; unsigned int samples = d->data.toUInt(12, false); if(samples == ~0u) { if(d->file && d->style != Fast) { samples = seekFinalIndex(); } else { samples = 0; } } d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0; d->sampleFrames = samples; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; } unsigned int WavPack::Properties::seekFinalIndex() { ByteVector blockID("wvpk", 4); long offset = d->streamLength; while(offset > 0) { offset = d->file->rfind(blockID, offset); if(offset == -1) return 0; d->file->seek(offset); ByteVector data = d->file->readBlock(32); if(data.size() != 32) return 0; const int version = data.toShort(8, false); if(version < MIN_STREAM_VERS || version > MAX_STREAM_VERS) continue; const unsigned int flags = data.toUInt(24, false); if(!(flags & FINAL_BLOCK)) return 0; const unsigned int blockIndex = data.toUInt(16, false); const unsigned int blockSamples = data.toUInt(20, false); return blockIndex + blockSamples; } return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/wavpack/wavpackproperties.h�����������������������������������������������������0000664�0000000�0000000�00000007176�12225024651�0021616�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2006 by Lukáš Lalinský email : lalinsky@gmail.com copyright : (C) 2004 by Allan Sandfeld Jensen email : kde@carewolf.org (original MPC implementation) ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, MA * * 02110-1301 USA * * * * Alternatively, this file is available under the Mozilla Public * * License Version 1.1. You may obtain a copy of the License at * * http://www.mozilla.org/MPL/ * ***************************************************************************/ #ifndef TAGLIB_WVPROPERTIES_H #define TAGLIB_WVPROPERTIES_H #include "taglib_export.h" #include "audioproperties.h" namespace TagLib { namespace WavPack { class File; static const uint HeaderSize = 32; //! An implementation of audio property reading for WavPack /*! * This reads the data from an WavPack stream found in the AudioProperties * API. */ class TAGLIB_EXPORT Properties : public AudioProperties { public: /*! * Create an instance of WavPack::Properties with the data read from the * ByteVector \a data. * * \deprecated This constructor will be dropped in favor of the one below * in a future version. */ Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); /*! * Create an instance of WavPack::Properties. */ // BIC: merge with the above constructor Properties(File *file, long streamLength, ReadStyle style = Average); /*! * Destroys this WavPack::Properties instance. */ virtual ~Properties(); // Reimplementations. virtual int length() const; virtual int bitrate() const; /*! * Returns the sample rate in Hz. 0 means unknown or custom. */ virtual int sampleRate() const; virtual int channels() const; /*! * Returns number of bits per sample. */ int bitsPerSample() const; uint sampleFrames() const; /*! * Returns WavPack version. */ int version() const; private: Properties(const Properties &); Properties &operator=(const Properties &); void read(); unsigned int seekFinalIndex(); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/xm/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014651�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/xm/xmfile.cpp�������������������������������������������������������������������0000664�0000000�0000000�00000037056�12225024651�0016654�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "tstringlist.h" #include "tdebug.h" #include "xmfile.h" #include "modfileprivate.h" #include "tpropertymap.h" #include <string.h> #include <algorithm> using namespace TagLib; using namespace XM; using TagLib::uint; using TagLib::ushort; using TagLib::ulong; /*! * The Reader classes are helpers to make handling of the stripped XM * format more easy. In the stripped XM format certain header sizes might * be smaller than one would expect. The fields that are not included * are then just some predefined valued (e.g. 0). * * Using these classes this code: * * if(headerSize >= 4) { * if(!readU16L(value1)) ERROR(); * if(headerSize >= 8) { * if(!readU16L(value2)) ERROR(); * if(headerSize >= 12) { * if(!readString(value3, 22)) ERROR(); * ... * } * } * } * * Becomes: * * StructReader header; * header.u16L(value1).u16L(value2).string(value3, 22). ...; * if(header.read(*this, headerSize) < std::min(header.size(), headerSize)) * ERROR(); * * Maybe if this is useful to other formats these classes can be moved to * their own public files. */ class Reader { public: virtual ~Reader() { } /*! * Reads associated values from \a file, but never reads more * then \a limit bytes. */ virtual uint read(TagLib::File &file, uint limit) = 0; /*! * Returns the number of bytes this reader would like to read. */ virtual uint size() const = 0; }; class SkipReader : public Reader { public: SkipReader(uint size) : m_size(size) { } uint read(TagLib::File &file, uint limit) { uint count = std::min(m_size, limit); file.seek(count, TagLib::File::Current); return count; } uint size() const { return m_size; } private: uint m_size; }; template<typename T> class ValueReader : public Reader { public: ValueReader(T &value) : value(value) { } protected: T &value; }; class StringReader : public ValueReader<String> { public: StringReader(String &string, uint size) : ValueReader<String>(string), m_size(size) { } uint read(TagLib::File &file, uint limit) { ByteVector data = file.readBlock(std::min(m_size, limit)); uint count = data.size(); int index = data.find((char) 0); if(index > -1) { data.resize(index); } data.replace((char) 0xff, ' '); value = data; return count; } uint size() const { return m_size; } private: uint m_size; }; class ByteReader : public ValueReader<uchar> { public: ByteReader(uchar &byte) : ValueReader<uchar>(byte) {} uint read(TagLib::File &file, uint limit) { ByteVector data = file.readBlock(std::min(1U,limit)); if(data.size() > 0) { value = data[0]; } return data.size(); } uint size() const { return 1; } }; template<typename T> class NumberReader : public ValueReader<T> { public: NumberReader(T &value, bool bigEndian) : ValueReader<T>(value), bigEndian(bigEndian) { } protected: bool bigEndian; }; class U16Reader : public NumberReader<ushort> { public: U16Reader(ushort &value, bool bigEndian) : NumberReader<ushort>(value, bigEndian) {} uint read(TagLib::File &file, uint limit) { ByteVector data = file.readBlock(std::min(2U,limit)); value = data.toUShort(bigEndian); return data.size(); } uint size() const { return 2; } }; class U32Reader : public NumberReader<ulong> { public: U32Reader(ulong &value, bool bigEndian = true) : NumberReader<ulong>(value, bigEndian) { } uint read(TagLib::File &file, uint limit) { ByteVector data = file.readBlock(std::min(4U,limit)); value = data.toUInt(bigEndian); return data.size(); } uint size() const { return 4; } }; class StructReader : public Reader { public: StructReader() { m_readers.setAutoDelete(true); } /*! * Add a nested reader. This reader takes ownership. */ StructReader &reader(Reader *reader) { m_readers.append(reader); return *this; } /*! * Don't read anything but skip \a size bytes. */ StructReader &skip(uint size) { m_readers.append(new SkipReader(size)); return *this; } /*! * Read a string of \a size characters (bytes) into \a string. */ StructReader &string(String &string, uint size) { m_readers.append(new StringReader(string, size)); return *this; } /*! * Read a byte into \a byte. */ StructReader &byte(uchar &byte) { m_readers.append(new ByteReader(byte)); return *this; } /*! * Read a unsigned 16 Bit integer into \a number. The byte order * is controlled by \a bigEndian. */ StructReader &u16(ushort &number, bool bigEndian) { m_readers.append(new U16Reader(number, bigEndian)); return *this; } /*! * Read a unsigned 16 Bit little endian integer into \a number. */ StructReader &u16L(ushort &number) { return u16(number, false); } /*! * Read a unsigned 16 Bit big endian integer into \a number. */ StructReader &u16B(ushort &number) { return u16(number, true); } /*! * Read a unsigned 32 Bit integer into \a number. The byte order * is controlled by \a bigEndian. */ StructReader &u32(ulong &number, bool bigEndian) { m_readers.append(new U32Reader(number, bigEndian)); return *this; } /*! * Read a unsigned 32 Bit little endian integer into \a number. */ StructReader &u32L(ulong &number) { return u32(number, false); } /*! * Read a unsigned 32 Bit big endian integer into \a number. */ StructReader &u32B(ulong &number) { return u32(number, true); } uint size() const { uint size = 0; for(List<Reader*>::ConstIterator i = m_readers.begin(); i != m_readers.end(); ++ i) { size += (*i)->size(); } return size; } uint read(TagLib::File &file, uint limit) { uint sumcount = 0; for(List<Reader*>::Iterator i = m_readers.begin(); limit > 0 && i != m_readers.end(); ++ i) { uint count = (*i)->read(file, limit); limit -= count; sumcount += count; } return sumcount; } private: List<Reader*> m_readers; }; class XM::File::FilePrivate { public: FilePrivate(AudioProperties::ReadStyle propertiesStyle) : tag(), properties(propertiesStyle) { } Mod::Tag tag; XM::Properties properties; }; XM::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(file), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } XM::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle propertiesStyle) : Mod::FileBase(stream), d(new FilePrivate(propertiesStyle)) { if(isOpen()) read(readProperties); } XM::File::~File() { delete d; } Mod::Tag *XM::File::tag() const { return &d->tag; } PropertyMap XM::File::properties() const { return d->tag.properties(); } PropertyMap XM::File::setProperties(const PropertyMap &properties) { return d->tag.setProperties(properties); } XM::Properties *XM::File::audioProperties() const { return &d->properties; } bool XM::File::save() { if(readOnly()) { debug("XM::File::save() - Cannot save to a read only file."); return false; } seek(17); writeString(d->tag.title(), 20); seek(1, Current); writeString(d->tag.trackerName(), 20); seek(2, Current); ulong headerSize = 0; if(!readU32L(headerSize)) return false; seek(2+2+2, Current); ushort patternCount = 0; ushort instrumentCount = 0; if(!readU16L(patternCount) || !readU16L(instrumentCount)) return false; seek(60 + headerSize); // need to read patterns again in order to seek to the instruments: for(ushort i = 0; i < patternCount; ++ i) { ulong patternHeaderLength = 0; if(!readU32L(patternHeaderLength) || patternHeaderLength < 4) return false; ushort dataSize = 0; StructReader pattern; pattern.skip(3).u16L(dataSize); uint count = pattern.read(*this, patternHeaderLength - 4U); if(count != std::min(patternHeaderLength - 4U, (ulong)pattern.size())) return false; seek(patternHeaderLength - (4 + count) + dataSize, Current); } StringList lines = d->tag.comment().split("\n"); uint sampleNameIndex = instrumentCount; for(ushort i = 0; i < instrumentCount; ++ i) { ulong instrumentHeaderSize = 0; if(!readU32L(instrumentHeaderSize) || instrumentHeaderSize < 4) return false; uint len = std::min(22UL, instrumentHeaderSize - 4U); if(i >= lines.size()) writeString(String::null, len); else writeString(lines[i], len); long offset = 0; if(instrumentHeaderSize >= 29U) { ushort sampleCount = 0; seek(1, Current); if(!readU16L(sampleCount)) return false; if(sampleCount > 0) { ulong sampleHeaderSize = 0; if(instrumentHeaderSize < 33U || !readU32L(sampleHeaderSize)) return false; // skip unhandeled header proportion: seek(instrumentHeaderSize - 33, Current); for(ushort j = 0; j < sampleCount; ++ j) { if(sampleHeaderSize > 4U) { ulong sampleLength = 0; if(!readU32L(sampleLength)) return false; offset += sampleLength; seek(std::min(sampleHeaderSize, 14UL), Current); if(sampleHeaderSize > 18U) { uint len = std::min(sampleHeaderSize - 18U, 22UL); if(sampleNameIndex >= lines.size()) writeString(String::null, len); else writeString(lines[sampleNameIndex ++], len); seek(sampleHeaderSize - (18U + len), Current); } } else { seek(sampleHeaderSize, Current); } } } else { offset = instrumentHeaderSize - 29; } } else { offset = instrumentHeaderSize - (4 + len); } seek(offset, Current); } return true; } void XM::File::read(bool) { if(!isOpen()) return; seek(0); ByteVector magic = readBlock(17); // it's all 0x00 for stripped XM files: READ_ASSERT(magic == "Extended Module: " || magic == ByteVector(17, 0)); READ_STRING(d->tag.setTitle, 20); READ_BYTE_AS(escape); // in stripped XM files this is 0x00: READ_ASSERT(escape == 0x1A || escape == 0x00); READ_STRING(d->tag.setTrackerName, 20); READ_U16L(d->properties.setVersion); READ_U32L_AS(headerSize); READ_ASSERT(headerSize >= 4); ushort length = 0; ushort restartPosition = 0; ushort channels = 0; ushort patternCount = 0; ushort instrumentCount = 0; ushort flags = 0; ushort tempo = 0; ushort bpmSpeed = 0; StructReader header; header.u16L(length) .u16L(restartPosition) .u16L(channels) .u16L(patternCount) .u16L(instrumentCount) .u16L(flags) .u16L(tempo) .u16L(bpmSpeed); uint count = header.read(*this, headerSize - 4U); uint size = std::min(headerSize - 4U, (ulong)header.size()); READ_ASSERT(count == size); d->properties.setLengthInPatterns(length); d->properties.setRestartPosition(restartPosition); d->properties.setChannels(channels); d->properties.setPatternCount(patternCount); d->properties.setInstrumentCount(instrumentCount); d->properties.setFlags(flags); d->properties.setTempo(tempo); d->properties.setBpmSpeed(bpmSpeed); seek(60 + headerSize); // read patterns: for(ushort i = 0; i < patternCount; ++ i) { READ_U32L_AS(patternHeaderLength); READ_ASSERT(patternHeaderLength >= 4); uchar packingType = 0; ushort rowCount = 0; ushort dataSize = 0; StructReader pattern; pattern.byte(packingType).u16L(rowCount).u16L(dataSize); uint count = pattern.read(*this, patternHeaderLength - 4U); READ_ASSERT(count == std::min(patternHeaderLength - 4U, (ulong)pattern.size())); seek(patternHeaderLength - (4 + count) + dataSize, Current); } StringList intrumentNames; StringList sampleNames; uint sumSampleCount = 0; // read instruments: for(ushort i = 0; i < instrumentCount; ++ i) { READ_U32L_AS(instrumentHeaderSize); READ_ASSERT(instrumentHeaderSize >= 4); String instrumentName; uchar instrumentType = 0; ushort sampleCount = 0; StructReader instrument; instrument.string(instrumentName, 22).byte(instrumentType).u16L(sampleCount); // 4 for instrumentHeaderSize uint count = 4 + instrument.read(*this, instrumentHeaderSize - 4U); READ_ASSERT(count == std::min(instrumentHeaderSize, (ulong)instrument.size() + 4)); ulong sampleHeaderSize = 0; long offset = 0; if(sampleCount > 0) { sumSampleCount += sampleCount; // wouldn't know which header size to assume otherwise: READ_ASSERT(instrumentHeaderSize >= count + 4 && readU32L(sampleHeaderSize)); // skip unhandeled header proportion: seek(instrumentHeaderSize - count - 4, Current); for(ushort j = 0; j < sampleCount; ++ j) { ulong sampleLength = 0; ulong loopStart = 0; ulong loopLength = 0; uchar volume = 0; uchar finetune = 0; uchar sampleType = 0; uchar panning = 0; uchar noteNumber = 0; uchar compression = 0; String sampleName; StructReader sample; sample.u32L(sampleLength) .u32L(loopStart) .u32L(loopLength) .byte(volume) .byte(finetune) .byte(sampleType) .byte(panning) .byte(noteNumber) .byte(compression) .string(sampleName, 22); uint count = sample.read(*this, sampleHeaderSize); READ_ASSERT(count == std::min(sampleHeaderSize, (ulong)sample.size())); // skip unhandeled header proportion: seek(sampleHeaderSize - count, Current); offset += sampleLength; sampleNames.append(sampleName); } } else { offset = instrumentHeaderSize - count; } intrumentNames.append(instrumentName); seek(offset, Current); } d->properties.setSampleCount(sumSampleCount); String comment(intrumentNames.toString("\n")); if(sampleNames.size() > 0) { comment += "\n"; comment += sampleNames.toString("\n"); } d->tag.setComment(comment); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/xm/xmfile.h���������������������������������������������������������������������0000664�0000000�0000000�00000007405�12225024651�0016314�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_XMFILE_H #define TAGLIB_XMFILE_H #include "tfile.h" #include "audioproperties.h" #include "taglib_export.h" #include "modfilebase.h" #include "modtag.h" #include "xmproperties.h" namespace TagLib { namespace XM { class TAGLIB_EXPORT File : public Mod::FileBase { public: /*! * Constructs an Extended Module file from \a file. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. */ File(FileName file, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Constructs an Extended Module file from \a stream. * * \note In the current implementation, both \a readProperties and * \a propertiesStyle are ignored. The audio properties are always * read. * * \note TagLib will *not* take ownership of the stream, the caller is * responsible for deleting it after the File object. */ File(IOStream *stream, bool readProperties = true, AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average); /*! * Destroys this instance of the File. */ virtual ~File(); Mod::Tag *tag() const; /*! * Implements the unified property interface -- export function. * Forwards to Mod::Tag::properties(). */ PropertyMap properties() const; /*! * Implements the unified property interface -- import function. * Forwards to Mod::Tag::setProperties(). */ PropertyMap setProperties(const PropertyMap &); /*! * Returns the XM::Properties for this file. If no audio properties * were read then this will return a null pointer. */ XM::Properties *audioProperties() const; /*! * Save the file. * This is the same as calling save(AllTags); * * \note Saving Extended Module tags is not supported. */ bool save(); private: File(const File &); File &operator=(const File &); void read(bool readProperties); class FilePrivate; FilePrivate *d; }; } } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/taglib/xm/xmproperties.cpp�������������������������������������������������������������0000664�0000000�0000000�00000007652�12225024651�0020130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright :(C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include "xmproperties.h" using namespace TagLib; using namespace XM; class XM::Properties::PropertiesPrivate { public: PropertiesPrivate() : lengthInPatterns(0), channels(0), version(0), restartPosition(0), patternCount(0), instrumentCount(0), sampleCount(0), flags(0), tempo(0), bpmSpeed(0) { } ushort lengthInPatterns; int channels; ushort version; ushort restartPosition; ushort patternCount; ushort instrumentCount; uint sampleCount; ushort flags; ushort tempo; ushort bpmSpeed; }; XM::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : AudioProperties(propertiesStyle), d(new PropertiesPrivate) { } XM::Properties::~Properties() { delete d; } int XM::Properties::length() const { return 0; } int XM::Properties::bitrate() const { return 0; } int XM::Properties::sampleRate() const { return 0; } int XM::Properties::channels() const { return d->channels; } TagLib::ushort XM::Properties::lengthInPatterns() const { return d->lengthInPatterns; } TagLib::ushort XM::Properties::version() const { return d->version; } TagLib::ushort XM::Properties::restartPosition() const { return d->restartPosition; } TagLib::ushort XM::Properties::patternCount() const { return d->patternCount; } TagLib::ushort XM::Properties::instrumentCount() const { return d->instrumentCount; } TagLib::uint XM::Properties::sampleCount() const { return d->sampleCount; } TagLib::ushort XM::Properties::flags() const { return d->flags; } TagLib::ushort XM::Properties::tempo() const { return d->tempo; } TagLib::ushort XM::Properties::bpmSpeed() const { return d->bpmSpeed; } void XM::Properties::setLengthInPatterns(ushort lengthInPatterns) { d->lengthInPatterns = lengthInPatterns; } void XM::Properties::setChannels(int channels) { d->channels = channels; } void XM::Properties::setVersion(ushort version) { d->version = version; } void XM::Properties::setRestartPosition(ushort restartPosition) { d->restartPosition = restartPosition; } void XM::Properties::setPatternCount(ushort patternCount) { d->patternCount = patternCount; } void XM::Properties::setInstrumentCount(ushort instrumentCount) { d->instrumentCount = instrumentCount; } void XM::Properties::setSampleCount(uint sampleCount) { d->sampleCount = sampleCount; } void XM::Properties::setFlags(ushort flags) { d->flags = flags; } void XM::Properties::setTempo(ushort tempo) { d->tempo = tempo; } void XM::Properties::setBpmSpeed(ushort bpmSpeed) { d->bpmSpeed = bpmSpeed; } ��������������������������������������������������������������������������������������taglib-1.9.1/taglib/xm/xmproperties.h���������������������������������������������������������������0000664�0000000�0000000�00000005655�12225024651�0017576�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #ifndef TAGLIB_XMPROPERTIES_H #define TAGLIB_XMPROPERTIES_H #include "taglib.h" #include "tstring.h" #include "audioproperties.h" namespace TagLib { namespace XM { class Properties : public AudioProperties { friend class File; public: /*! Flag bits. */ enum { LinearFreqTable = 1 // otherwise its the amiga freq. table }; Properties(AudioProperties::ReadStyle propertiesStyle); virtual ~Properties(); int length() const; int bitrate() const; int sampleRate() const; int channels() const; ushort lengthInPatterns() const; ushort version() const; ushort restartPosition() const; ushort patternCount() const; ushort instrumentCount() const; uint sampleCount() const; ushort flags() const; ushort tempo() const; ushort bpmSpeed() const; void setChannels(int channels); void setLengthInPatterns(ushort lengthInPatterns); void setVersion(ushort version); void setRestartPosition(ushort restartPosition); void setPatternCount(ushort patternCount); void setInstrumentCount(ushort instrumentCount); void setSampleCount(uint sampleCount); void setFlags(ushort flags); void setTempo(ushort tempo); void setBpmSpeed(ushort bpmSpeed); private: Properties(const Properties&); Properties &operator=(const Properties&); class PropertiesPrivate; PropertiesPrivate *d; }; } } #endif �����������������������������������������������������������������������������������taglib-1.9.1/tests/���������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0014125�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/CMakeLists.txt�������������������������������������������������������������������0000664�0000000�0000000�00000004210�12225024651�0016662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../taglib ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/toolkit ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ape ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/asf ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v1 ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2 ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2/frames ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpc ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mp4 ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff/aiff ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff/wav ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/trueaudio ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/vorbis ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/flac ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/speex ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/opus ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/flac ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/wavpack ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mod ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/s3m ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/it ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/xm ) SET(test_runner_SRCS main.cpp test_list.cpp test_map.cpp test_mpeg.cpp test_synchdata.cpp test_trueaudio.cpp test_bytevector.cpp test_bytevectorlist.cpp test_bytevectorstream.cpp test_string.cpp test_propertymap.cpp test_fileref.cpp test_id3v1.cpp test_id3v2.cpp test_xiphcomment.cpp test_aiff.cpp test_riff.cpp test_ogg.cpp test_oggflac.cpp test_flac.cpp test_flacpicture.cpp test_flacunknownmetadatablock.cpp test_ape.cpp test_apetag.cpp test_wav.cpp test_info.cpp test_wavpack.cpp test_mp4.cpp test_mp4item.cpp test_mp4coverart.cpp test_asf.cpp test_mod.cpp test_s3m.cpp test_it.cpp test_xm.cpp test_mpc.cpp test_opus.cpp ) INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIR}) ADD_EXECUTABLE(test_runner ${test_runner_SRCS}) TARGET_LINK_LIBRARIES(test_runner tag ${CPPUNIT_LIBRARIES}) ADD_TEST(test_runner test_runner) ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -V DEPENDS test_runner) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12225024651�0015036�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/005411.id3������������������������������������������������������������������0000664�0000000�0000000�00000113002�12225024651�0016166�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ID3���+xWCOM���q��http://www.amazon.com/exec/obidos/ASIN/B0000024VP/softpointer-20?dev-t=D17H5OIRRQ5XUC%26camp=2025%26link_code=xm2COMM������eng�APIC�����image/jpg���JFIF�������C�  !"$"$�C�,,"������������ ����}�!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������� ���w�!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz� ��?�9aQ(T|g'ZN = 9QHF1RR=i\d{}FaI3R(qG4E1?1F^jZP; 20 H˃H H@#ҤǦ(+AqRf:)vgA=F(o<?ZC!+(O^ o4Gր! :� ^3hzf{TRrOJ.!3ڝrzzb dRsJ�`ǯJ@;g"|P9A0!IF>Scڸ;RqALSm'#0G=)ʗ\�PF)�`!1h=| \GOtLBqPP_ʦry֛u} ?wJەFa f�/@Զ MȨz;Ʋ2WF(Vn"U\�ÿ5݇:Jj;w/M/'Mx5-7D ]w(�1�*�6G4nxis{bVM7�\f)7si_ׁ-~O iC8u6FyaH2r/R^a/Z}sӀ'}k?9nW8\}Q]#KqLj=MRƫ9uCK@?>3o ޿R�i r%>"?N�cT}{vS6Nz5-.ϯ�QG&vX*|=;/;׮x?c<�L4yRd>ׅ]1%*Ź9mnMh+�OͻTRq?ws3ݼ 8RRuX5ź! ݵ=O_֕<[U88{Q??=C7h?"8o}x@p[ZOK<< zi㩘g�E??=ɗo)GX~+;[4Ş*8г:G8�?Z?g߇cބmTނW'|6N?]y,}?ϵ4a4,:?>$��>gsnTಯ5>?tM"*EL1qG�9)=5@q?_ʼ;F�1�L9|w+�ė~E.߉wj滶QיT_ƣmGN jV ܠZ�qyrԋKcV 0 �])_4~',ڶ`|i_JOx~6 'tdn7:'쯵?O_ Z—WdY H=? >Uİ2$"Q& �$w8WZVIV�� $Baw$/^ר{㱮#!l�L )>707=xJ_a&8�G}=}hoW0́nSC\4�u8<?n-K@W2B&rxsLl& :ׁgoIk�zЌu]ޙ� YdgӦ3\a~K<Hː>EfA8'<S.Yh!O[:0p98G):⽤{s!w ^r7Zl+aw]wnā$o\2;W�幾PK{[X̨@]I n}\ƈMkI{�F[j!5K996=m�ik'WӢfeH Ն3mcՔZK,>>\\DqyYrQ NZ]׵Jy7 O@ �'<f5:sh馴uEl|k?Y[XwHN\-נ4y%4v[+lgqhzzԥJ/':5`ȥJC+d?jO{K|$<w{5)QC>n>rr8e" ^$4)M>Y>\@|;ehΔ=9w])iWٴno'UGo[.k8D.!*�n^Z+ XivE&X^i.YzXF9+wtu+TRk7 F| `vZ᭏J~!x`F�bHl٭�h\鐠6]YdV!*ry�gzǧi>=ԠB[%p;g{ŷMU\^ؓ{66pA�?g~Wpx+f]K̚zg W3^5 O>"^u;Tyݺc\xlɲo)8N de�'r:�:vxgEӭD APHʒ Tl^YZH3Gs!yo$ScUa<#�w:C0V+ӻz;gE"v#^Ic�&GIigKޕa5oږ&h헍*?SǠIY܈DksqA\X) Iy?g+߽űɅ w |+{<xF&X8�͏^<'KX"[VD׳<]V ty&o͠N)Dw��s da5LDYTmt'ZҮش/lcx|s֡cgsw"e>ߏ:jP />HoJ~B}ľ!Ҵue+ P8!'[5k:vrkȡ$S"cZe9; BV-7½kN^+�f4v_QpdCZ_xonmQ64%Ums[=EpG5 zKsH3 ?ɭ$uˈC.1<59,W}t^6)c޽J{6ofQ\ %z2r7cҡ3 .]i O�c+ܾjc宷}E2O\.Dl$=H+%æ[Cyg'$47 =C URJ ;]8DK$h,͵T $5W 5|ȳs'rHP?e%xé޸@b4 䵘}RL+E<2;JԫB;Z]zmKY<y][ ֺI4/Ѹ`pq 6XYG~t ~cדO;][F4Ų)B75aVVߖ ei$c<3>l�S5);on�JAil$;~m>jukʳy =J9Gt-i.&XRIZ5؀7ާ+7 Wru{嵆(mDCal1H;T"W0 fڻ=:>o*`Jq$j4]}Pr)۶ʒB_%Žm:4gwdH:g 묠 òZwsh2$VhgtUgmbI׵m_Mx7;ȈŶ ;%䡉WQ^v]j읓]ZXj2Zt Tx/\;e Bŏ�ZRJҒbZA$N,mi,{O_^{ >.[[s 2V\1'N+K m5m +oi4f,@*Ԓk((_=WwݴVv Z'M,o00 %}0:VF�ρ�#�6q=$mʟg}Td�9yo$%)VXՑЂ 8"j ^6�7P#\?km'PO0_�W>5]]OoxAoeHNb1�Y×|#]ok{�+˛'?5:cƃ=xy?g}_֫%KuW3Z{-1"6~�|OH׼Unquw͘q�~֯fouˏQh~1n=Ϧr kNvɤ S`}pӏ7:=�KcʬG ,+g �f$l$Oс0=Gq]7 W!b+cHV>̱`=zW5 K%G /40HAq@~a_OF:uSK;ןg.[]̲׃Vv1~'L`MtKri׺J< E7sǡ+oړj59BزX ˟ٿ�+.¯/+>�..i^8̎rNI8Oʹ�m> \ oCg|7Fw+*9�@$XҺO]ik$_=8_0|}=ëMPRO):[*r?"ZѤV?7dr>Щ>ײL?IuM58d =9|]ĺ.>@zFp8sF`}IqT+OF6rF81һ\K|Rm2[,zc(G~G�JBYxAfJ@9xzj4{+<!=2k4iԣ7-�kx/Z"_1~{rHϦAڼ'n7}]Ӿ )'DՂɓ2Σi6 ZRp79±K-[_<q3*pn )rܱz |׬$4~FᶫI dA99p4Լ}s yZt ha;*�s5κ!I$WBvUR#)בRUIKcoS]-%Ԡv5�VR?ŜA~_ӯ%V9x=Fvf5x2Ğ4HpV1hA<$tIDY>{ SMm6/u _e!=U=A8;cFygф{3bYPdcёVS" ? ӝIν`�*,zӡ 3űvՐ.�V-<3>mFs垹,cرv�fy*w$9ZUV Fȍq {TwM &%'[~l(yzW;:S/OlH{!M7Q[M^/-uPOM<An{|K�cUB;[f|x�mk_.L>_=12w�>9qji)5W ��z|0o.l-KɒY.En4X+:@�5ɊP{5%.xK7tP6:FAA^iV?-'bZ"Pp@8 I1֮EwlFwi:\򆍓ۆP�p+({0FcyP]`[P9:.jr{i[-+ʜD[m:{]?J_6<r0dyqU%וu33:B�;p˕lqXI24*4D9@vsBU5I/oQ\I)ATsۉ>,4J-?=4�3:JxMSп.qiw,7>`^A4i$3  VSu6FE2bF@?J n 7f(![(eI߸O%I=\9HhLeC?kJxSVm䖽uGbu)-[o,x_KˣcY.{hôjO !'@� c$EpO(ܤƜAzx ėYy2d+(/dv`6}H#$`gx�9TU*1)zk}_]μhK?w_BܗPĉ pkFrefq=+v1g(yX#B@�RNm\KkUIsi @uZ_o&ŶrH.UG^yuyU7Mv=g  ܂2B>xge uc�8t^}ZtiVf%Ң·T)f9z)KGL(ʵNXfvWᴿm<xY!(Xl $Btg::1l /mGZ(r-R�xM'�9]G>DTac$d[z`xSQw� XZe$0 TB-)}ȇJʛﭾˣ:t|y3\2 g q dq<g.N\ȲB݁�# z>ꭡZEƒ\~h2nـ;[*Wx-G_jꡆBh4QZmM:m?ƞ+I-T0(ܐ ø^6_mNMK7SXs@lYNlTڌxJ<G'��8Wf_O*te?.||m-nH/cVnXW*�8<g#d/*7\򥶟q][x3 8^MtDIqؑ#޻pUCjַ_z{)}6|p 188k/3<= ԭ`!ARJY`+pvM{1u*_'�(XC!VqtqK0GFX\J�RO➵ QѯP(ïpp 3ֽ|;}ZOJ\[]/LvH=}ZZ>jqӦj|"e#>.G9cW,R);0%˩}igY-fdYDy(<QJUyu4RXir;nykKMLX#NSڟ6l%<8enO/ Rs�"/Zk^y,*.SR=<k i� Cŗz՜ ,HDj$o 1!I\ڟv\i7Si,\eO d0=CGkW3tV:m@$. 1F<'Vuۧu |@kNWgyw73m ɀFepn|} 㕳Ҿ0BSvL0 gԒ+Q@ؓ2d, n3N=-�>Krħʃ<�ڻ/7 ܮ[A~Ĝ2�3C+{R-_Δ|!sK_vpO ]go~\t9"gx� aؓҵ<xKI,!6Cp0e'*ss^]/$v# |8扛X{N+ǽ%7�Z׽s~5{m( Ln$PI;NTt KPMӭሊ%y$']`oֺ]:YnV:Ds<Z4r\T$v�9+0A^J_fM$g8NתW^tOkֶG+k{v R!K\[O$.B iQ'ʐ#0;y5/{~!IQ b ƤmV$ I, s粺 KK`MH%jנc1uckiVhjV{\oڅ{z/&xLBQӠiT8B"yg|dB9+]|1mF)REkKxάRYrIj/=GRi=U$xC+Go R8T9˱׼oyh g${lıkKiK~JrTeaUl#b޻ZyiTMc]ĺN7VKT x[,5ce- ͸ pqd9 9~j0N%o5?%X,nw+NWAe#\, *:ʫ:ʕ�;8'":\d䭪]}.uzUjUh:U_M6/ _:~w h-m%lr00# 'ƫ[Yk4M|ڒL''>kmU*\^EsQ" {,[$Fd=�%[q9n xRރhmg:#U[~l$֕猃;M_j)[]VoOK_ԋQF RvAQ,dJr2{ut3\tm!yt ~Vmov*Ga7<5l�mmSR{p[ɸ nl3ԎlY#:,q99'>=ջKߞƭdmtVڄ$Y4^iCs!~`:V%|l͂0G>ľ'ؠ=DF ‡3tG uY]}�5.8>} gQv<>$�iӭ#%@˹ pUۗu KEr{}]N[j(UΉԬu8 <cK+g: 'vwB&?1 t8S4_uSO2lLp£R3nm̹\ʾhg";o`p�A2Iz} zR,\}&7e:tvZO %'h/ʻ'9\cP.|.aˁ�WQ)Ky'LMAx{漏 >JrWvrYUT&ADZv& "A9\08PreVjy{ݮ?ϽlU>;fJuR1uKF(H;8B~P^G׏jt$Hչa:mc ZH[M%"0GLV)фծ;YeP{E'SKed3IVN bGr8jss\�A4 �hnʍ'}KTe(c|`}:ծ:t9g+p쒏kJ}8LHdTv'6�ZglS,h]^9 (,u=VWʬq�SOSuot813ﶌhw�DqolvKPCD5sWmQ%FÍ#8:Tzv"b F9}A(8sŧ1.U%%ת2--%g}XdO8?J[Iλ9Uȟ^*UMʓĖz| Ry ǷWRwc/LTQUFWEZn+obvwm0\]Ml啘�#׃:RBn N3!?[!My+#z:�?jb%,CbaX¢q\v]kˠ/`D6q~ΠkdDeݿ*镔B>}?ƹ3W f&<e�4SNrvÇLξNt{.ݼ#E<#r $R  +B~ZגhሼK ҋ{{|كJ{st<yW?srE"\8�qֽ'E񆹣i-m7{YZS 2 SNO8\Fnl$#"8�A k,0Ӈk]?3ͱNu%eӭsƚψ|T蚝ZB㳷FXĒ] �ɦıs ŔL5u/ݰHD67œ�Kt5Wq?OY^!XYB8iEr'tz`52oݔE=CG3GK"=ˈx@dnZCrxViv{AЖ{->8[{x.@7�\ j� cQ6T4hde!lwm.Ѥ{@@\A[0xXXC[c퇯R_&Hi^k3J"1,Þ)@$C2H,gkǜd9׽?~q=S|�¹ӳ<ڗ2܆%UBFҤnSF#'RA$gN]Ci$XװE�wH8=*1aڑH#϶jwrFA<z9gŅ8m&WHwv1i!%gq.<]۝i^v,nu VD=qlݶG;rvgDr`َ�{Wk:7,-"HYIqЩԊ+ �#xZ4_כM<=[H=vCf;F-¨ʹ=xMq4vb֓; GF1d1 lxKF<SkjJ'lG;pz �HNw6m|Bu"98ăj9zcT-I{f }(<X{%G }_2g<g=+Yn~כB)ЛBx<DڻJ6TJ |}֪ At5:[Ma{UO 0\ak�֩Ȋm�g�)!V:06' ptA&݃j@`3r=?5g*ݎ0}o�w=LٿPm#p~w班S 7$�5~o@�~f {B:wnmMs?$w *'9\?jK-H;zi=At0?xN1ۈm)Xv#Ru{ڍV_aJWzld_YM rQw~]Ai[aO8C*ˍIIF8Q`ax�kA*Pi30dUlТh5+çMjpYH#?ʲ펷5Ԓ(63.=~^d ahL@<+kC֧Yk 5demT>ѱa} 1> vןU { c�<86]N$$tN?;[9Pd"@?3�ץBqEFv8l�jыC!9-}r�\�A:q忾~e�?tgA�~?O+Ƣs}[6U]O7.Ox�KFqn$H O ^�>!�izg�|4duN+_Tu�O"]y.BPxou֓xex8v?JaH?J¢?x_'nQ8waU% (8=?3u0 =Ġf'G5cWR�g 3zU`pp$�ZE(+#.¼ ΚwxOI#&]z�~}ju?i)#o'+Ưޟ.'8=Fss�֤�q�\MX�XHޗ@;p9#4ǡ鉈y4rN>)�g~ ښ@W5⼛r߹yM2Tgzs~(Gk芳G�һKt߼}ӝ�?d?n_yď_IAh(7W{#y-!t@�kR/g!#i"1l1Gx/^TtL7U\GE2Ij6siWϮ^ı޸‹bT�mFl@A5�i@pt*33Ldi$v%ݛ,NI=suZG(]npOG+reK(JRK[wN^Xst\_bݲ6GʚXM 2(+TO jKGU W! +Iw_低I@eHz*O !=_fi= Iģ�^iۃѳpT9U˚i]?4flk[DM]UNz`�zZė4Q4Arc$? ѡ)cv&qxx$e^L 9Gש)[tӷ**\ ѯC=/U{nBUǽU�y`#v%{z~5ƄiToyExba7Y-ܽ;/5[ķ,{h`}xYifZ9 #?_( {YX:3|Źe)E?yn]WNͿ-ntGYR!t Nh_}:I'KNHH �]qгgq,3�[<M)ܠlL#QUy SeNOH6P؅Qzgon"BNP{vbjŦ˹@L`~zƮV>gr}DkHٶRRX|ީ8`/8cɞ9?J%9^D<Wj7zd/nA9:{^(qJ[F55$Zx+ej2Āњ4%S' )OuIm]c}ۆ۵}qL6 V-7`V3vcBTaVW+)e1t?yliL'��c�SVݤ�2c*@|�e9z塮AW/oS �@\>}++)kH,=ؐ'>�NU<:41Jmr2>�T"�LN@ 뤵GKhdgjqನ(5qo#r>+҆vyO x}v[1}N8j 4/"\_�_r9$Ŏv|voWOcFA<ݷRr?.�WyF$pO\GGAgmݓ4 N#�/ZdU?^=GNPq�PxF1wkCۢ_CM]�\ϋ܎㟙xO;ANNpOd<WêGX5 TBJ<LN͡@_+ d57 ƧMf{L[iv' Y'AW�Zt%*umudMOKU[wݯڈG�zן[E%8 �<Ҷw/H'?*6]'r3c;VVXjdufMSr[Tq~IS'j^iJ#-oD=DѾGB=y�J%Q䟕:Uxu) }l+"̤w"ھMՎ[/}K2KErUۙ|޿zK.6@܋/sdU_ [NIQ�VtpLL;fr03 #Z�y]:Ӧފqz�$l;e~^8F3ko�0x?ԌUJ,%#ʤs?:f,,G^y?Npr28k&XεUxF3h�`矗񪚍ZJ�m'$�F1;by�cz\|ogBPE�랦LDҏ/sxOt[Zt[v]<{\Lf?y0NҠI`O/I8'Ssv?2H3<}5% B_Җ{DqCOҦEu3` d}8[9ecyS~̹<?Cڳ2>Bg'V݄&\A B0EunԹ%"ܷ;w�]{[Y#s4l =-אiqMrc(lX #'>:k-g4<, � w<r4']D DQ\cqvxW((r8Շש;dK)N|z##Mefp dci^-ZT~ <ҽe:m&FSlZ2tzUK&5#rmx#z"?|HR6Lc$y):XY|%LLO^jGX8+P;>Y0zOexkw*6l.Ҵ$~}ki�3+3k[-+`0r:($l$\~o+H 1,�Y+2k))fC'F6粖߶3C hRdkӑ?_U$T:P_A'@k۲�,1 ufg_?͋p}=0in{n '9qcb1Ӷ(ls#E41^x={hayܓrF8 21i9*zGҘdǦ2?s>,w[Xaw5tG^�?r,VmB"�GvCB}!L ʹii}<_//RnZ穯ST7p?u�xR77 ֖"- R ^}?Z.lpNOOfUg#>�?Z&nG$@#a^KGq//=p$o $+dI5�sSHTG?' ]2[:y4ᐆ\ i0_?@t ˏqߵr>m<tv#F T8_Tsa0+jƜ[i_,x̼KDc=V̇2x3&rr:E#'3tG_z5N +ARZ�M%*ct@`3x׍BA<9WNi2L6xRUQ$^#1g=y#�{uŋɶ|W5'nONH>b{]%qKhv)�s`uMNeո !`}A^ݓ‘Hђer~\?YŸ4O gg=Ϙ~]1zԼmZ\2cz�.kۻi[jEnH'�.;r~j2iڜ֓; LK 222oҒZX|A?]vr\)$Jw2;x'_]..vE #b=Aׯ [(m[�9t(۩ܑ[ [-6DmnIӎs֔{eJKT] ĞH?*=枰m?"lu#=_E蚎s54TiYg0HKO9n' �/kRS9RMjCi|ഖa<2N ݎ�@В3[oJV�'?)'g^W᩸R)}_JkGT_yd0cko"e Xcr#IrA8ְ4-Ŵ ~hmM|Y>!�?Y>`TpOz{d{PwۯjpUfq��^pGsֶɫ2�IG8_^檽,wAzzќU8>KejsJؠˏ5�gwn0>eoL~u_Lx~IdԡF+�ڿ$Ly3vq?,ң-;⾧I�)0Xz6לs}i3ܟÚdp1u=餜s84ᓁAU#?:]FV} Cc_?t cCҹ?6N0H< B+Qr7z�xr0Ioʾ qlb:NXQ::) �#O_Mvz{JdPUI;OПOjƛ"C<ݎ`G'^+Ь$??Yx?;0xִXd`% )D$#z/Xj^_s4" #t :j@#=WQ}۬Frsל>$/+좽|Ź]xnu03)E_}e�g }ri TG0Ii^G8I$kRsԦ7}qY̱?u<d^Ð~?T  vmRBHh'w֪?sy[g'U_ЎqvyJ[L9Np {,׏oW<r$IiK[YIn2[yN9?ZxOL"8=y'�,i62_y " g#H`$L`8#v'N/RRi2\>e9w0?.++:-\Is2Ydf_Ӯt  9 yyctQ\zq�*%h͹9 o- +y#ךg׵x'qqev0 Iy+"i.t ;GD;0:@jI1Tr# ?i(Nriμ[gxSψ%7E?5 zWO? M^[,2;cy^" ԖZ/= >Tߒ;E˷f>9<c+<|miJp]3'޿.raS$3\{DZV<޽ބگ[P?1L2pOׂFQWQ2wƴ5W_:Ё(=3[^ 0R$2܎?<V$ ci $hw;`шq~dq.R\|oRwW/qpA']U`zU;d@=A'G2lohʔrkEs8*Gݦ~.f̙ '~V?w>rX=OӃM}j&Mg?Uֵ(.59Yaמ& VbO*֧QE(GAbdž~E雕Q!Հ nan}jHd{+v$UsYc�] Gn 0xgqOKv\KsfҜ}Kp3 q t` ӊwVg s?t xO҃�Y<D lUg;?j_XtW$ǁ9{k�.[@=~fGyc j}d:'lx8�G[{1ox [;'k�~?!qku�kЌcNKk.bB6N�'bm|\�ZZ >*Icvֽ p).jA٥e� rc#|S1Ok+02m-OLry�?ʲl5mFEw ##|`OOҾj.viFE)ICIG_ uiYH)c&2??ҺU]cg;_HR@kMF_e) c"VBg~H�~̩HԲ@M8=NbW $?Ƿ^*BXq8<0;pM} fH[kg7L6I,@ (`J00<�/v. &%d�ň 8Gjz-֓\iӇ/o.mCr{Nkīu;xbc+?K?oѵ[KibF"Iʀw `nðSҢAlEE�ʌ`{?J]Rs=?GOo"sC)9㎕%htL0xoȎ(؂!=\S@[ q?v[&UYTǽpӒku.SSӴ˫rv#� 7cOn}~v[\<R#/cq^aKCӤ4ɡOؐA\uztpkn{<XBNTxD 98M8t8_iw+33yvtbe'�I :ͅYnϴm+arɩ$i0�y$5ڷ nP0O_Ϸ_]SV>KZR-Đ̭ щ-]/ s_+MNۚi"݌gk) `ʾz-e䛒7�ݾEڥм1%Csr2&1<"Y ,܎~k"Ȑdk?]vO=cxrП_QC/ht^'# ZlvXƐ�Ӡ 0<1s$E*U:\`w;G/M6Y:.�$W5﯒H!EbrW r9MqiWYPv9`ŠT}?8f:fשSۇlA\vU8lRxkgvO}9Du.I>cU30Ẁ<ҕѽ47/ H` B=kxgG:1ʹ6d] 3` ZJ.S{i箿֧F&RVO]{)2ۥ|29�(E%qnYhXVRrT#5Ťia?3�:dc]u$;Y] hҖ+'׾[\9*0'dˌq y5n.--TȞ8IE =<dU-ZHEU.K;'ϓ<�O z6ZxkM.Ov81[q,ʫV*֛/.Z㡖QTVC"QX6w""-bT@22G/99&E+IͬNn/78!A c=k]Zƙ+G#SǸʮx1=.рF1#د:EkV{=}6M|~Qݻ}{S�-A�MҼ^z0~|ld|S3O}>ㄥFqoV�Ec1*�9�<<9툸{Z^lkp .3O~Uky~h. |8" mV'x㝤c58G�iznW<#cgs:-ۙh~mu\$+&M4tzߧܫ 9�eb/7H&�W##TyHm_etٛeIZr@s7 :K 7~R9С(u%pFG'wf&2F�=:THZ3\$} FN}ow4܌c�1�)JrN9dqӎZ=5.s }g N�ɖJџB|9&۲R7sVIei&vLLɒ9=ۜnX_covcH d{NJ|yyf8cRy<vjTo,C5+%&ףw_5~mwa5?hTaݷ+"A�NHO^_6Mw ][}O9;tz?eyvWJ I$ Sۭxx$vSr3PÓUIH_u]Eq 2x9?oº趗oo1yc^UHHtv^k%_8\g:Z?(,bgϲ&xjK JW0o1V<t沴OϦ\MubmeU w$�FQڥEu{]LD%8Wc XCIoOzbs[SZSTA9U🊵k+OUլŲ7 Da X}Kӥx3˪IJ qn{?5 rNgJ5;/Ho )2Is|4^^<^i\{rX^ +E~_:kjhJ79ߜ~UxZ[l298:;?*"!rO݅we D "11+7+*K՚qg[ߚ^WVQ֦͜⬷;wEmj{q#�X~!V(PX4\C[gO qbk:/1S?/*G)|cOJ@{{orPutoZd(nw`u;/;�$h4''1lGxHϷҬXX[GzLjZH\>Ҳ$υmT%UfP@/Azw/HԦmJ^ٛ1t860�Y IV^[..FXynԚWkⅿ.sN ى$TrHsT<55t6z"-]G$m,:F8Ďxݳm3nW |>¼u)rFSNWk_Om[.V9FQz|^DP:n;(Ђ3Ж-wy%@pNTFz;R,eY\e[{t/!N$A+ve#GpQrO}k�uùÖֵm2_E~r0O; ]!O9#PNۖ+Q5E =6_Zⴭ7TӵI,-e#goD;2A O^M]ִdx[k-q�@F2NAU#^.q--﫺z[}3 RmkY]%^]�0Z<5uOI "qٱ^/?Zot14P#q)#`WWWzx#C^F\!hwp�b.Kztohpvr y<r7'<IZݗשҜGi ~7_1 n_>>/^x3FVhF;[[DUV ǖ=j/P߂2[F0�]enlm4yo\;)rdgBfni6--}:u*ERm4MyGEuj<-e#!GcYE^6xVܭA?ֽ/EfY.+Fc q,[qi6=᳔:Ѻ7>Xda#RٿMonUum뛕]}ҵ@wPOrx'hã~_n{W"\ף&'tA/wL?gϊ}S/ySNZ_5)/~g1ϧݸ?6oqoL2Χc諚_e.dOb?ES1 zVK6/W}՝繋�jH�<}Af; H9*/Gn5[�aoj\EuGEjʐ?�8xcN{I[=|6iC 9|2Mٯ5wLRKk6AVyµ|wm<ryN6tk* N:ygOP؝cyԖw3Zx)b7+wG8Ƙ `RX;K%yu~<FC+xѣ @"%T`3zVV46#XcOj({vA N/Wښhzut{ےr"cG#Nx<Wwu�xcJY&hlCu<%ͅݽ[\KnU2$~ OsĖ<_=徭iH|@+13qgt<u0Щg;Xk#~*ni̻M+@ed}kPX֮:=xUK9<<_n_g4fo_1 L/%ǂܸ@:cWti._qL<exsL=&yϟ4X Z݋T3k-²9>WuU[6ꑓ,ao"=ws>/}fOh&CA)e8 L5~osl% B7oԞ!nk-mYE1he,9U 9|fGO�ZY^JLg\Y50*)b:;z(7Ua!�[� dߥ tpSx˻6#�+K{-"C9UO $|�8�m'ܜ�� Se�~kRXj꒼~|ɻ}s6c?tZ�m/~׀�7].G}aN?�Z_=oY¿w�H<25�ewd]no%b? cm>SA�u?.%�?kp~gş:�?$;Z<1x$,Db(1g~Z*9;#x6;{ I@-\ gQ 2p0FG=k?dOx(D*XF99S~cT1Qny "&BrpqcԪ+ߧGqPJnw͏MxSM �T%T3t#AŴ!GH޼825qoﰒ��sIVuZkf=daC&} |Q^>/ %%=<fj?{W{âKq潤qcWw !䌆 yMSL 6l&^\{-=Q3,G?_e-Rx7HHh = aSW}/nY6kZZ7X.,].kI-/DdVB=c[ABHX%9*8PKG15򃫪r9G8]G4Z,l=돹,놎{*o=LEeFIwi|=a5te`Iq?Zڧ9tsZ6ۻ>=p_kyDGV85F46˨Jۧu$3s6?دP񵥾]& J+g ;2HOӀy^A4W>hmbZH hNnT8{%$jKGV#U�$vQ|HD/e(`>iF;Uh#00iA;o+F%v[vNXw$H|w�98cm1Lk㯭y4q32/BQ%u_zcT&#�_}|:>\d0<Sapy.2ÐqWsr GC Rn)r9̠�*|;oSx9M师~||Oj͝2{v& W Ӟk?ckV�[�QycyЗ,HuXRO۟�֭APA w`J  �5oΌ[Q"`˰~�Ҍ!R&b%ߜ{[FOͷ{wի]ٲ!R?]h�lMaqehD0G\j֥Z;^bOےd~^9x( \$`~ǡU> R9.0͵匦Vr7/n_C Gsm.(ېHǦqozh7koٓ$s(l/9Wo/֊~W+^yngSNWki[Fnze/vvK %UBB^ (p{m}\k0jZ1ۓX*ƮpUT` .<.=56 ڨ-'~PQ :3h#U z~[,9'Njw9VIV?H5ߞ?.iZq dyۀ@d1kH5MBBy',NכZmirCeSy-8<:̒=Ēͻ;FI$H$x8ERQMﮬ4J&W|�vLk+iy7e1#>P;s{ב7ͨ^Fg26$~>n~Q*m-exgh#p2N3>=A40X?1[ʭ<-YF.oiK+|-.k|M[kܩ>,1Fx}g�p?s-Zksr k2ۤX}O_āڲ<`m;XFI<Yի'V=ԭ+Q]#aFt{#7gf9<Z֚L)rNWF*FrN3qúV�סG(%wM~;KvnUWI|sjTs2s|7ATm8k}t��r~lQy]OZSM�/xDpp?U%|Z�[ $vz7Lr4[R14{IϨPd.>k{kKɵۀ'ֶor<Im.g�,syMH}RLLJܱۨo_lj^oJ˫ٯ Oe' =:)0w(c&Si 8[X5 LIrpe 6G&Y$Bݱa,w1-Bw1ƫ*6fcedҦKmɗQc�C# ~)3'Zw}emlao~̉'P۔ v9[^f=29/Bu F[�NN;O |8X֯?9Xb;U9%9/:q @Uh�`�:^UJе~5Jj<¶sRkmJm/TB𲝍<d-2LOF<I<bI$ri-llv"73 -$�,N��>G^+وTKwD83v G\}zCYj:-|$e�ݺ|ǎ_֞$:}ܓ'KSfI�R89<5KZT纽KSSiK`B81L3ϷJ>;\YjpEZ{PyIQ$xk`"b�\_C`[nZxۙ7&AF}Ř<W]*8XUw+ӭu0_Z%{Y~= >xz}!1 El4sYFۑڕֻMCZ<0G;Z,es'5kJvMHPeHdž';J?'ֵRZyk4M[7%c˓5{ʬԖ}~+Y7}YiԔT�'XV�3R^I}^}{5ܰ}ƊhTU{ڕBQ?<I*qO^�<[ōʘ`Ԁr?*Ϋ<qn̞u1C r�@Y~+vwH٘: \<^)SXI-uu}o4Qn@[g;Q= +Kl7=On;TH’d=G<jwzťʫrKdt4RnJmlȖ"ztZ7ٟ$�t'ݯҚ>%ɑ@y \q$Vx2p7 (ϏGTَ4T*pHMv^z|6/K $Mq롫 [h_E_þn-U[kiYiOV#<~K="ʁUnj1t=*p͓˨Q9'&ݺ^~Ec ?j &x̂FA#'k�*w,:g3oOjif rϿ%9Ƶ*~Υz=aүyŷk[#SQ+X<YyI A֬[%j $ tTۻ470mݞ_shZ^[\ۤ<w3{^+VW%ޫ{t`fc>y3`f+Kҧ+�A�Vі7RIEURw#] Yǔ8ktyRv|6GKG{(;BQ}we2h<M;Fr5S1NGvGk3N rp=ys4֓$70"*`g?T`I'd'N 6pū[M*e�Y *ʞOBr3 .lt[RU늡ᦆpd�d JQkuek慾鉯a`:\~ڶ+byʎŸVqk. xJ"Nq˚ћQaudBxsN9ږDaW]�93 \P8.sv 6:+FqL8_ĎxOS񞙧^,R2>ۆ{1߿Jê^iVKM&v. K$qpZ]rp\to=^%+RNWVI},atKqeoջ"KjvS{95FMm~4Ah"fmm% ǧCyI7#JۥæfcDI<zס�zqsx俫?y=~!VMMVSŅyޒ@AFWv^Ơ#r>+hFkxR"U#dM$uq775.񇉵 6IUHJpHa{v6w=W>%4G_*BY97WZ%#m'KI]V3#IE-I?/:$pm>X"cq<98!6W_'Vdc3ʚhcNnԉTҟ:tmLŬ@s< [W:M6ʲj\Wq;3�ni4_ mwrq #aOj!? !ڿ 8'֦C:I{oċl4KA۷h$WzGtۑR䠑-c$?2$(bRI~%OPDG8[{* ]ϬJ*|s}+VFӳپ-�#أB.6Z^zGxԗF&5]n!8`ؖih8 \ּ1-֩ 6Z>BL1 <g4Vm[X;ssw(#7Zƫy$%vvgfzkB&2QqvztՕӲW}}8<S~4x- Sԅ*p\'VEB:-#8rdC$ -ıd|Rh#Jt'\,ovT$yk' AWYYi܁q( @o.џm]Æ9TG*W'hW^碲pU~#Ŷpd l/Db< ]3)+Z٤t�uSr>2ƃ,OѼ'\A17K(U;A1^2YiW= Y'J{1+UqnnF{IQm${X+DCxb (9\*S,qǧ]g(51Bʭuuw!TfXm!?@<!mg w},{0? c洉\.dm�RI}#x= g<MUy}8D)w:S{xRRVDѣtq@8H.{^S A ? Ş (K$Ӷb6I2p 8QX~+:MWKl}'6E34F^V/6Uk*R7/_kv̲$6rSN6=3ּHVσJKƟDcrpr{k֮>(j[Z%9%2`>䃍p7 <K*i9|DdiW+2;LqMPh[^Gmz E7*r��umE]ly1 5zM;M嶷u_ Rt `N'uW^gmN J Mk>"PJ6wtk<9wtH.4}!~\!pcsc*_SgN߽Uo2Fz.ze[C{<+<P@v_zjk;V Otj탌A<\|Guچ-k{pK따cdp3ʯ=;֯tI 6Яkۻi\ `b|ng_ ZU*’^e{tZ^4k!ͮh1Z ߆pۂI%a9}φfUi|E{"+'Ě75ӮEY"C`k2`Ԫj̕u%ռ+pa < q*yJԆM&v{z i[mR| 2'R<6މ9_֨\|)Ynۧ2RT$drrv5牥RPɺ;t<,Eʎz:Ӵ; gG9 (&EI8ZOdkq�I~N�xv@z`L>m $9R˓t=TEyV ІՑ?7X-ݢ4q s[ 4Wt1e3÷؈û0Xq;c,O XMY6CT)T[ El-⵼ɘg�k?iyv3BPX�{t'zmX_jEYP0�3cT_/.g!ү#A9LO۔pG^4]L7g|y��|8-5i^v1_pHL�.}zwcnCOHl4%eˆeQ[n+ᇉE:Ǥܳ}v϶yϽw> m5�ϥK<w8xk7T+bs) eqF>Vjo337.:%m֝÷MNøB4g\�A'j60G} ŜHUXg,ɷ�ӽz{c]4|~dH�n' (<wyruyS˥nSD �2I8� OƼ[o/Bf/<ij<Z9%*@p^T] ]umR Oiv]c}uX1n2Ǥ#Z%xG{;,ֈn>2хE[�_LYf-$1C C�1n9UYUHw[Ky6D3{:!}Nsf ,dAoq9euoцӑ۶#($x]ˎEpCd#{{Ta%%o&s&ETAxzZsGgglQc|꠩4ENI({v s[IGE<ҁiCn;/UImx@2b4k׫7ruz3"M#X�,@$p2@U~/B~ؾ 1 RO+#E$m}$~dS :"2OS>?3(=4n?y%tЃѿ9_E/pXxN]=C%ż!pom E;IaTk|S]jL_ZjwYOeLFumYw?^գ݌PyI;C^(Xy{9Ti.ߩ*y}~G-7NVs\ bمͼq}gIk#Q<4VgP�<8Rk1mA|i$*9TuyUi2? �ɃQ:SWn\d(ÑٽZ]3ÚMy&<y;ս xeV6mˁՉ'e_p@.su?zT'8blk,p!ך,m ӯ]6g}cLG”-mzomKvm<?цC<鹲4;JhూK4pB~zdbn'_ plw *ؑ{ӎgބ}O=azٷ%f/$p-ޟlk-<Ah+Iu jsyEad'T >oIk<)_I�fQ'<b ؠu'tr,^eD1۹ �$z/j0yZWI|[aUq!`=Cz)a0wm_[ZmcXXWe/|1gy=Fqq9sBLWqWOcW5 %D1oe ̍=8QO5j-)-;XOv1gTg])Y)]n-;f\LK:}wW<:^v~47Z|pU眅U͍+vh(.% ]؍N �kIԭlE(UUr0:MմGTkBPm{3wϡ *8vվp7/9xB+ [}fsFIaY '[_zn[)y*'flV{S82BoHN9޴5.WӠ-o-.i0im9<sJ[CNsm<Q$MC| WsyjZ&&㳝%c93?&]3q0,mv;x.QƷ2DEXI;�:ƍjrZ/t]W� J乲bx``8}cJtY,l넒eVA 6qqIxe;/o[<YQsMgv⼞C>,GG$*G� ROI+YуO T[u:_ɣ4OvV WA 荑ƴ#x{E]X[-aBi= 4uPw 0Fk;K}Y$͈K[B3N9y1q\[^j=Cr(2` gsOF˞zZY;mNxV߶[m&uH#xfاjO'USOmF+ 8泍L@\+t n{c Mr%ܜ ?^1ҳGg.<i$hۄg®8p8q_A<N[鵼V9yZ-|5εiiDҨe{2L,t}vk--;}=d^v@Fb:;J۵m44-g$UPs?:_[",J&X_D1I9ۜ˖8=9QWu<Zy)SkggGuc^DŽ�XvDR`_{r 6Ma"`Y!kFw`䦓c[}L"? ܄S$u]MSN7[ݽȼ((E;pXNkl6B}~vx)ͫ 5uVwyvC Uv1{�E`x7 ՛Vvdq#cWa u;GJ5K+RN.$ES߸Pn>k2kdb{gn8<և5X-rSs)ۑԞ$;qNIio�J7xn7ʺ-`0  kmZݠ Ip\"7OH$];XA`rWO_&I%}伮ij;,|ē� WW<bmϏ4Y*n.#Qgڄ,0Np:4-b `"'`TO1y*v88[m?ٞ"S�`;RI@<s]P'5>*N!H<:-kE[�JDy~Rl(s֥^& )YnI' ׭s� w?{ۜy_Oެï ^x:5߯^N T76`8<gƭ�$i'z"Vɳ׀Ѯ{sAOT4O%.X#~| xU d8FP{TdtJe9$56 =Q`<{DO\~܏#&}NTKdK.@rq\c# )^Ja\g-߿ʍ4\@~-PHݜw% !RH�Z\[qLu4�L L!s0.G-�<P\dI� :ԩ �wRT3�M$sV̞M2o#s=BR�<qGӟ­dmYJʇ⃃emԷV#,_НOOoZ\r�52#m?#'Im5 zi<gR?J<�= O1 \1'xzt*�M u?�!a}y0;Ӗ0X{۠$z☈u�8Q'\_ZOzVzt 61Ҥ1�77M\n�4{�ƍ'S`u,ln��3'H7LsBX'4ƈFbGVaMFs n.Y8t=Y�:�TIT2������Sunshine Superman�TPE1��� ���Donovan�TALB������Sunshine Superman�TRCK������1�TDRC������1966�TCON������(80)���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/64bit.mp4�������������������������������������������������������������������0000664�0000000�0000000�00000000125�12225024651�0016406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������moov�������M���udta�������=���meta�������-�������!ilst���cpil���data��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/broken-tenc.id3�������������������������������������������������������������0000664�0000000�0000000�00000000620�12225024651�0017644�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ID3����TENC��� �WXXX������TCOP�����TOPE�����COMM���h���engiTunNORM� 0000036C 000003E6 00000BC1 00000BC3 000186E5 000186CE 00004ACA 00005A82 00011170 00011170�TCMP������1�TIT2��� ���Take On Me�TPE1������A Ha�TALB������1985�TRCK������1�TDRC������1985�TCON������80s�@���K���� p����.��� ��%������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/changed.mod�����������������������������������������������������������������0000664�0000000�0000000�00000006074�12225024651�0017137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������changed title�������This line will be trun���@���This line is ok.���������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@�����������������������������������������������������������������������������������������������������������������������������������8CHN����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/changed.s3m�����������������������������������������������������������������0000664�0000000�0000000�00000001040�12225024651�0017046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������changed title���������������������� �SCRM@}0�����������      �������������������������������������������������������������������@��� ��������������This is an instrument name!���������������������������������@��� ��������������Module file formats�����������������������������������������@��� ��������������abuse instrument names��������������������������������������@��� ��������������as multiline comments.��������������������������������������@��� ��������������---------------------------�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/changed.xm������������������������������������������������������������������0000664�0000000�0000000�00000012537�12225024651�0017005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Extended Module: changed title�������TagLib������������������������}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����@����Instrument names��������(�����������������������������������������������������������������������������������������������������@� �@������������������������������������������� � � �������������������������������������������������������������������������������������@����Sample names����������������������@����are sometimes�����������are abused as�����������(�����������������������������������������������������������������������������������������������������@� �@������������������������������������������� � � �������������������������������������������������������������������������������������@����also abused as����������comments in�������������(�����������������������������������������������������������������������������������������������������@� �@������������������������������������������� � � �������������������������������������������������������������������������������������@����comments.�������������������������@�����������������������������module file formats.��������======================��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/click.mpc�������������������������������������������������������������������0000664�0000000�0000000�00000003064�12225024651�0016627�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������MP+���\gg��Йs4}>|n"vKd"墲*{eiy\=sy4g/cX@Occ{҄-y^g2<DGjQ(5 lYR1ElŤ.<*0ZP>;ZK'?I%.]$Q(w%3V�I9_x{zÿLvZhߞ0|6H }7ܤ>_I]Y-&D.;"0I,H)zZb>sϱ ӷ]g;l*,/*'o֕ 5H6P&C(jAon]~пB8 xqKrJy=A8p:P1(iĝ7X?ZE?l:яӼ1F8Tp=|'mX/D*H hrn@{j-y-B^ BN9qL6.[`[&dN"hG Nc].h>;R'=2L<N7nc͔K H^2{fUt R{:r2q%L&9$ws> ǽ>{E0织F6/""K{|̜ [ĞK~zw69UTUDDWvB}|*^l] wLxInL sGSTI*}{O nQi5urNl i�m;IZX\^&ЖV*UAޮhn ȇYQ|8VM3yll mS33a)IqeZ9[f[-+gրOE uG&WG5&6|_{;V]sϤL/O} ۚ\%1b- ZU̓RT}:pFg+i}WiY<l[.cSfZzglnw= <S*b<zPz_v[o۞*ӈ{z=vpgf*Sjg禮ؑ#xs{RYo7$ Dp29|շvZ!#^% yyӤmnM<<g~ΟӞ3sϟg39{ϺaI%|Lq! `Y^H> �y럻+)2n$pմs9doZ���W dǩdoz۶mےcpz_UUU]?Vt.\tپpkU`__G뼪j$ҤLT<UU~r�[U5]ţK BUUuVAP~��:����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/click.wv��������������������������������������������������������������������0000664�0000000�0000000�00000006150�12225024651�0016503�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������wvpk` ���� ������ ��1!RIFF$6��WAVEfmt �����D�����data�6��BWWGVH�tH�%J��������������, e�����?~��p~aD4fLA�Y)4�!�p =`ɞEyPhI=LI]F"��tCד% V�@ l�j4$8M  t <�^xt؁K�@'Ͱ3@?#,�ƅ>@0L&Y: 4Lp !�^A˿c倫?7_}֟9cyfOʊw<u1#R$2,ƽ] é2hd"+x /Y"U,:ZnT_dMA <v18P!@a�r X!4 ((5@A0x 됒*duBBbapaDQ67D>LqHwLP-kjY3oM~lZ0 &.Pӈ5Ԙ.11VO50`#AG>7)Ŏ h1ƛʊ¢CsBxf,7EzM9dGżj .AEc,p)pr `,<X:s`Z;љ%` $ p7`TIbaxŖ yW2<M!F2MжENLw͍a� ;8P$& JeAB@A5r̴XWV"O$]w3IVXu7et}tRE |x8cߖ׿c6 R褬C? L4OR@yù<zPdcU1Lj<LOX><>D!bGgñ;d %cˤ7R Bjc6{Wrqh0];pT~t=M0sМfCEʇJH bY5bA6$L+EA⇀Ep@6 ]#̂uM=Mefax؁`H2_xspA噙4"^DP(YC1L;�ð!chVXొsx)iLa�<%S'=O2SN F1 9?qpdq, ːG!DcF s#c!F2Āw8pA4Ԉ21"�όv/Fw9sR=$X6OP*98L@s[:W d0L}Pf5 ;3x8pYy#oyN%@$<A/m LȖ20<%th0$S m~ q BQn0yYЉ=A(A:!β7wNACa(B�E8 A縑XwCcp;2C<1Qo/w3@w�% a+qfѻ:ec{4,GW]pQMHuѢyAI){2 8Ĺ!Cɐq) 3GzBxDtL3.խ?H(U1�sSb}S-:a.pW_߮c%yP;, LIUSVE"')Apgyi86D&x)HCϑ9$EjHАEaY$�U0H<XVj 66X\RduFQ#X4x`rVfFZ"u@(03>"� eIs`̶$!`2mr`bXi ޿R";WGH`5B8b踡@TBuOrq9%fԁ> a@1e9dA^CJAV\>diQ \=_"+]�ZDrSX)h=X0 _DJSfΒG1VLxC)\a,S,#@=@,GZF|:D!2GPƁI$RW._)y4=- lASYQFT`W<;:4haʆ 0B)OA7s4Nv! 2eSĉ3kP_A#"TA,` 2<`R 3ZpA;r  5h(LG:o9|  v]9Ț]SYHp`ƴ4)]!v0e F8 Dž�hDp,F!+햍=U y!dt\3I=\" GB^䡈;~Vҁi8L$3)A 6$0P "&,eaMz@ʂhʷ3t%&"FABgSQv jQ"HgaGB",r,gB0�T(J{#n[v`$<0s#DI\ ,# e9 ;-#(ܪ6TC p|ɳ` փOyc�Z�2oD3 "t<2>X0/�!$BO`;ΙA=Ąa눒 ckȗrx4!FCC!1 wV<_�`!!o'Fjag c)$([n/ 0t4OuNZ<m0&KmbC!0K08 AP|8MO,p-(2gOO|r? h�p@" �pCGCu0EB* +h,pdID#�PFA��؃t��03 D OA<����3`3�0L˶ B 8 #4T3:J_h������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/compressed_id3_frame.mp3����������������������������������������������������0000664�0000000�0000000�00000011610�12225024651�0021533�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ID3����,4APIC��]��Qx[W?m^Z[* *]EAn" \D.Q{*[ fhJfggə9LLݿk_\hђU[43^ixޢ?sK]-|._yC o w!.Ğ߅+v1ZiFb/Ś\5Bb/W^*KXU^! w]ٻ*t1{W7GٻI657>Z|^>N+bϯ="jkLrad*wm4.$VL hMd*yj3,({'@vjLjagoֺy 1ͤzoG(Y+<~xݬ,|woaNvltDz$w@ւg~(3e[+<~`c%vGp& fb]V܂kFs3*F6k!vk e aGk4u {;-XnBS ƚwg\Q9t3�xVgFc!Inmu?.vanW.PYc{ 6̮Ⱥ*=#Z>'ad"\E,?dro^3سpn.i|X–_j+U{ ΜY*a-Jf`fj+:<E|>֜,(i= O,ʭ3Q̟Zk Z>r]`2cϲKA 2zeibB6[MZ惉rBg4/pIRWĞ_{~EWĞSY'+bϯ="+bϯ="+bϯ={¯0{~Eٿ1ׯ^__|955 c[b>3@ ̓###Ϟ=;ֱ'&&el �Ӿt֖wuu~t1FGAw(=& j+**4Maa7^RRRVVV]]]__~bO<AGA@a>էJx8s쬫+..HHHxbdddDDޣbcc $/ Ư@f] 訪ZJu̙�__Ç{{{`?88ٳ)))mmm_a .\ ؾ}-[6oތm۶ٳ~~~NWHOOG\hhh@@2>T dL 566�ݻiӦu֭Z_r5k֬_ڵ= ,, ;"?@~Zك2vX-n<$'o_9ν7Y|ٲe6l8tɓ'#._~aɿOn>@HA )ޭ[T~gE/.]|knݺu߾}AAAV1@GgBH.@Ƙ-/>3�Gb(yA Xr# 55Ν;>ĸ_a@ϟ?v= ؏"~0}~7?/{FGG/8{+6nܸz{{]}~#e0x}www=}t,WH1$s=%۶o ht:WHA(qU#߿cV֡/^Ge_ty^lܹs777##R7gT:>^^^MMM^b'>$Ş^vs=hU|yGx_PP�ɓ߼$Y%7Lq}`` "veך=Bl(ږPܾ'R1M2O$׋< WTiiiab0s�{#rc]UUe^~ { _o\t: {8y:wvvίW8bmUA 2|$z(#8&g W4]]5'r>7IWǏF/..dFt`0{iZb?@ɚ>$~bd^`_]]H􉽰go4AWWܹİ /ٙ^^Xsb-(Y֏ufL72cֆ&vo6} "š{ F ZCCCee[al~3>b/,؃nҪ@zrD}vg3>b/72B/ O{FA?{RI�{6G+!c/D}{zzFGG`o4 &NEEE~~?>c[kKPBG?00099Ie سHj 477#7 {a9(Ͽy&}^BBl'7n&Mz`w ab/9t _SSىtojjjNA\ަa?22n<}:nppP:sM9=-l:ӯD/:M9̞= 0;o<TC`\x&;^Zy4)) n%/9|mgbbѣGWؾW\�{v6z2c>>|s2훐�}6|CGCCCpα}aAv!~7 }}}wMd{EjtMub;":zYYIߟ&&&555IboSse^Vr-~z^|v|Ңhbݾg;;`{zz3$5w۔x8s5|zRlǸc?bGi>۔=xv3ڜvua| 1z#8{Hf�ݍ0K)�Y^ss3< ޚCmJ= [p0kWGx>lX/rMYKtA#0Fqqqc>~#A7{Y.,,0v+**T*USx٧E\@z/HDmʒ}AA,7$n Kt1W}R<G"6e;Φ܃:Ą>dEJg35boS9 =v옷+XOr;Ѐ@ޞ۔%˗/;w@{i ҲﴷkGGGK3{d|󍧧Ν;w{g߁RU=gEMY<rݻ7o޼~ k]k0~n-*,#o۶mM->k^XhhHMY?ѳKŞė~FI<!boSŗ5 AʉD{{_ZvǏO%=c>:|;GFt~'(b/&{ʸFt2o$⚕}Ne6 orrR#"bgzBcc#{z\{K{1\]] o.؋&%o[N$J-I!0z^/Ǥ)b/&AOꦦ&|$9s eee]]]r'(b/&k1;rssz{{ ;'{1Yї`hǦi^\)f~0U逈SSΛ2|WS"be#3/.j iʜD rycSe^\_n{_lOO,ezأ4|PGgn.wo$b{?lƠds,zcjF0l�Fbϳ="+bϯ="s*q^"+bϯ="+bϯ="+bϯ=r=-_= w!.Ğ-{Z\WOAR������POPM�����������TRCK������TCON��� ���Techno-DanceCOMM������eng�TYER������TALB��� ���<Undefined>TPE1������MobyTIT2������Braveheart Theme (Techno remix���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/correctness_gain_silent_output.opus�����������������������������������������0000664�0000000�0000000�00000105262�12225024651�0024302�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS���������m����",OpusHeadx�����OggS����������m��� +OpusTags���libopus 0.9.11-66-g64c2dd7���%���ENCODER=Xiph.Org Opus testvectormaker���TESTDESCRIPTION=This sample must be silent or very quiet. If you can hear speech without turning the volume up very high the opus output gain is being handled incorrectly. This file also has random modeswitches.OggS��������m���)ܘBCCd@ @k B\` (h}tO,++~( rNS __?jہč7/{oFe����������������9 ,Ze$>a/UAgp @ _h9sIpײڈ0^|E;dGW{??p}L%8zjFs83AO �U| Aa,/i9-;~%^,#qᜪ<u̯nИzh6WccudzA+i7_sX8@e| B4"뾘% V ù.P Xp:Qכ 2Xf:mqn/kъxKu~+`TG/>B,$:+)a8|9iˆpĨ/n ߚJm =H/N);afn0G6%KgA˩=M'9f8&wh.t^\Ņ_Ik(,;M.mmY%[f+hs39Nڸ|9]F ey1+nn媵/Xh¸lΒo6 .y �u3 Q<Zp ,`&HHra ?d@ܞFGKeN|T FE?:nCy;(!1+Dž+^+(u!,[G[7wX2w]8 P "y~!F1O[t M1Bd uImnrՈ4z{ Θ[&ҪZ/:$(# ?~*w3\)% tQ>&mw0U(x<\Df?s̕xm>чRɜJv2D!ަnxYpΤjfiQtUȢ:Fױir,W=LqaOWִzkMUy�)c̒VA@on5!-G[v9T3.BԴE-$ NvY;Dj0DtBZfa[ �-%&�61.I$B>2nsn5=H\,}bw1=*,Z6\pBVa  vl.afzƮ$ۜSN0ύonTɋ |3a#vGKoPj-T E0r3VIX+ Nj\�B =9;3A #ګHbql֍d)㳐*SEYi}Sn;oWTPI;[_PWJ�)r.)JrcPeN,5J\H TM!2KSǼkGi`&ըn{~\%" Yk}7о:;{ANײ}gx($]O1|uCGl~<?ߞt E7.T.}�;F0wѠ25αf"ه_z�#ƺ6:Xڏ(r215@[Uk`~P5K<Ѣ?}\k! jku齩S3\F3.QoF9;gbw}_Y.:^&I}"; -7(+@"ē}3Ee "B>^ܨ>N.lm/h)swAOŎ8Jz=~ ؛{g>0 n kUMkm3#Z%�"߀*ڸXZ9,&J>~!B_(t(]N`MtcƱUŽV<7}8<f3&GN?� GI?2[xAh]:&RۤtCus(G^3bYgaS,p6~(*[{(G$^K[2>�AXB` ; ^<k&2} O!VXN*4s‘]ugndTb;&OmbGL'.)ᆃ%Ŷuy;:k9 1}b%ßC_lMÊ> _># R\Z*K }yIBNJ9BYܯHg`ffԓs~X㌨8T_z*?SeCM1i.?\eZpgw]vƐ2MKi -$ 1 uj0>Da$#NK(Ɠ9yhˆ(;;�N nrcpqȚ< (JnOnCCh7<k dЙRvs+W7-Oy&ZIZQZDKIzVD~ǀz9^יZѠOggS��0������m���aCl xAWOggS��?�����m���:7 ιڪgCuFe#$1!"xhgGlLljKzۅŴEBDCF Հz.CLt ^+Qx5/fktqbkmײrY$0ffxڦ8ߢ`#i=Lb̔nhv~jhۨhHдZt ۓpkhif_>}j05d)!~ZR[;G7gsvFF-$v PDM x,W_:pQ~\;mvko$D&?\�i&$ ~ea]m' ]'ewdx_{,1pYP'>KBPC۴8Q/&بǯ}Jr3^? 3BSf 0q<>ˤDs4]ZlGyreŹ=b3)ǠS+Ĩ ffZsB{ 1Ì\\ܔ.g$-"jj' 3F]utG[urQ6 BX94#~WZΣ bm>+x(8#ÛDtjЂ W#eik)-fDn%p3E~tTKxT"V/t>eBҧ4ʺ0- �ek3aOq+ sk6 'fu|bw`3f{)ŗM%ۃRtI>2r5�xDfЉnhIPաɸW�Ÿ0AyDS6{[)ÔUQ5?*bY̔o+5cV 'kfRc/{?b\6;dLsfȃ0ڂ$^mbl.TD!jVL;M�ݱBc<ֻk:rJ_U&SK)Mݬy;ciA e~lCն4�c!`+3C30+OO@P�OQĴ9dS'a F8ы&d^EojitWY9W%F#Yod$d%)=؁&SmT*uzC~,Dz&W:ctxR-47 L9)TߵHLNl Մ Aq] 3œr, !2ݥ4ml!) 6gYXޑG:Z9hND8i;=L!$`- TGk�tZ /iĖ%X |sKYSo"Y92J`2pWbl)=OOm㚯 `O ]y^}/@;=#!<PEK:FՃ8�lh۝)zZ#< ǜK6#Bsb{0#Ƭ;pux(#F_A SfKl(puO :ul] j G=sG|wQAVB&ioҌixhMֆ}-~mr:)]h֯H@~G)+geUZ{B)ȖR()Kftj)'VanDCt76_1iK y8%~Tm ̫[ͦ$md@fcAVV h|UavbGX*:bڿj/5G=dPgm1Vl~IEpS[́To-D^PdC*Ω|+e {^o07yQPM=(M\\wvu}ψPJ|Rad0{7+k<bDI0.D(9Iݗcbd]Da\Er>~a=[s#^@We@GcF^[Ha0mYXޢo"vbWo Z,p Ҵ4"ƹسyOu5ʧKZTJK)F&ygἊuymQ\q'>Vƌ;earf8 ~IٳiLwy�$^&pn&AF Ogsմ!eqJ4McNf˶sE(yc}*KelpƮΏ2vQ}4s`{I (!PSϬPAEO2TqI wp:#?%L/zVzlK^ =$+?c1ߋ,P  S)=E8ɼ ЧI=FROv)�_] FLl 2(;8givu"M2ѐ.[1eF<C\~lm[Բ^\h\sbJh\8p & k.wZW�o}v` R75tcx*E,@%Ok1Z"qm\DyGLs%/*5ɰN b޼QQN~k:kRUu5<]E."@L@jŔv6⟬LjUad|:1}C`nBvwh7?=:Xrh:@έˊ%ʩIbw#bF'MB%]|nJS}cVlc2B*'PCXZ_n2'HFpYy<"ٛ/>>ei%W"4OǹScʎ!}g G;+Fgc `Irވ,)ʼf'7h]RjƎqHX0U!LAIĶ5c`?[K1H /$=3yƇ^2u?L|馭3G0KY9JQ^! șnAhjk(uh\LcӒ䖇H1.|3Md9_oJ|h%7f6^.^nG7%Tͨ E Bb eFo3bh{=jY*Oou[R1Gzh`hۗG&= ,�wV[?Qyi<*±b)k}~C\ҋT7A4iFC_VOݧ-II8o{TjdT4Q}ܲߞ\odu~xZѧ`$_NW7=efeo}@BiAQIs5^p05= *[gfKԺ3ðYJJyt` NZx?ܐCeo0߻{J3>lZ�4J9/{LTqƠV٤ NʃÒ 8ԫxo͸B5t Le8oI18s]+ٜAe)oT%zx+aboꄰCvj)Q1`?d3 eҠ:e ί 龛yG^kujQ+=nf\7+^pJy?:87e̗Z3 k5 E =>SwG嚲B>r�]Yr],JnFrf=[8Y HJ k4eo& [>Tp̏7o[+g2b %'+#{ᘨp'|@p]$h2zƈ̒ZtQWcY�_gN\{fF.-Yk&F}s*'ޣ3<0g 3E)_)?oj84nUwJĜ�֗=vxl$pJGOFfyDx{?Au[Uq}#ŎJ{YrGDŀvRM;hh y& :cn#ox[a`ch|8FЈoG*Ԣś%mQnżC{f!~uF5) c"}a~^eusQ]7jngz0C}31BSW, v[|\l8)Vњ+u7) lkjDwjn &PP健/`½&OV$;o;Ea4(Y҃_MՌ'파�6s2e@OI.j:=p$Uof2L[V3K$ig fLn\/ aDc O%GP5i>h7k G DZ+k.OggS�������m���u/fdbnD./6"!BCCAq҂ CFedrަɦtqppij5lQwINyȤCL]w^KQH}1"!r]KE*t Y[0T?yZ$R?#[[Rjqj|.=qVhVx{jM8 7|7Us2Oo3vSE^Lo?in qHRY*2.Knq a\V Mʍ|R7uUT3&Zfi!,^Dm_2,Ah;qWmU&O{<u pQL2Ϡƽ(xTɟ׃@t^KT"Loͽ"Ta*`H<_ ·ȉIg,x[*ꕒ71Kʄ\w_cn!aʂ(Ć8޵gqE8KēzYb<-H @NH?#sI߱J袉Tá!]k/cp;IQ}wNək/tW0ꌧˆRW!y?j7[RAoM^e d><{eÕo}h$p�  SͶ 7/ 'Ɨw^s"2t {z)[;?$퉅Da}Mʾ&$W<Is&Ci5Ms?X߈Rx6ı$@5<kb [dti3D^NґTzQ{bu^nP"ſi4ˌH v(Nr2.AꎪfR+LS ]@$AC rƠz +w=1||ߑMz{MM- {\ZZw$A(FN쩎PwkݢOC}�7w2's%^K,c:gJS h[5SJ Y1qDfj!!==9 I3]$ qpxxg0 C;;*!h v)|;~ {\`h5HJ=y=ҥB{jFcmG,ZyCh:Z~ [CVj]Y dsq|n,3:Hk# åzJ#4ův'/aE?xqغ  i`hMHqHtM|lsvWe$k+"U|_,JbY*b'oh .x/~"]ݿ/1>IewIT:(7N8OWLBVdZI8950V^{صhڞp9È ^(`E`NS}w0h %"oltwy2xO.;YO!#vٱ<tzn HclKr[0(od�<?$Xtɍ8rJdZldu6bV(gqzF^~5DS de\mxV G0%X�%*ݰqgEύ-D=4*Y Jn<58]JFV;Wަ #s~YSy; t 0pK`iM/ dmfcp>x.3)<k�"}mrpV<C~IjXvR#ܒˈhHUR,h.y^_jH*K݁-~F m\;.䗷�U=Ƥ_-'>e؝Һy|Ah ! ~ҟ 0A5ԟi};Eթ K!$1qUWcn~~fxE& ~k$Aut=MԿqnf;kĂ;$>u,$xtA~XV b^H0P_3ݔʕo0Ck$/ })R l950dI u"% K�w %Zz&j_aq]JTB[= zW̘7>O2N=m,g_ݵeBkPH蚧Ī@a U֊f2GBbj#PmaH'\P5*沦0JY`~D'piNKրO_'r' !رs>�֟E:UY,q=ԅ-'bſ @W+9V?xD.λySR?^{mý_@7 <TnrxAcj9@~g<pb ]Aj%<Ͷr@o'5 Dg&ց>٧1}YE!U6) wٸ5B*j_~}`+=~~k ӆ?\.#sdB|͌YBKz05zdM4Əp3YOz=^Eʀz˗^ohr4,��rl$YjY=>"^x"GyX Y�6[hTpm -j肅q\2g2}gQZE1:AOH*^;YUd||yXUe^~2JS\N-g_ڏm8Z,햍޼*<]yfeȋM\BIe8HlH|֩b\-𛚮p*7pCE8d5*zzc>V4:�$ L/y{9(*M #['p*|6H.\-Vp~x^! PG`T!vou`}~<zxЎ? {Ki9)?n z/[txmx+[kqS]OCz&ƷNƉ@Uis*UFgf4EK.GMh}uliR1jxe\ "9/,IE#j6Ǿl"3HGhfy2dVRM ؈p~T i(ga&?޴ K "!L3v@ͼU~݈cI0y 1xI PQ?/{ |v2/g%E.l) WZ9 R~ ), 1qJ?FB6; ӟaXdcq0 ݷUb+x" hדw&9Jaf^? ʹm Ťm~>LWD&#d<g-&RBN5ƙup@?%c~.,g*lɳ6 ם9 ]-ʝ=l_f~ëX΋\;aj,}+QD9 ̠86MUqF%Wd!څ/8vB2zz&m^ 0g5YEOgg\`.AYʃI,aj:6WA_jK'~,BR{^=L CdpEGBⲱ)'B ˜ -o%qvif%/9˾V{JQ� /3j-yc T3]iH�^Zv~o drq۫0W‹fW)Ek%blKY\?Nba1:>\YoHkE$L )O<'^ʇ0ko'( d$Ş %Uc#n[jVJ0׼l3=KfUgtzanS03Wxݵ!F"|"[A8÷;8zݦknq5${}ܱ�ҷBtBcϚsrꑁ!c)b*ĢH8D o)m NqMGj˜mRwf(=|N%iq Qb`3!=# 4�l4 +UTM#]-xFs`' MrCsکm` =)/"ɓT҅4Ub?ܨ7OqnXtY >Ea2vo|]^SwoOSWZ%_Q﯋,\Sq'F&o=ko ;TBMy.$7yE? o}E05[ IC |?1]rz1ݔ^RBR<aw "C kDrQ[F6&'@`w3yYlp.<GFϭ)x@ƻI,wZnrQo\WiTqYr>jCڸkѦ˱ U>L`]Z[ ʩ9]~ Q)}v$pB!b#Wf(̤&I7\�#(%Fc!)gcj|kY wةR><DH4QiOggS��X�����m��� Y:qՈզ} coAadbona@ߡ٭ɥ ,; wAgY۾BfB4|72~/eYq} Q h#z_>ے()?3H免mEvME-lfj2Q rnF>To|ԗ4֤ nI{G(YW:#,ץ力RUUu. 5T]1<真 HTl54%<3vF PgZj֏7 +O=7D _BK3D>w>" =1TbB/:d!oq-,؛{SH|qOK|euŗFDjSiyPp#~K. +PcʥҴ^dƐ4 4➬'$>Қp)j+#.^!nMqy(D_Kt?[xLLZ}Bacj31d^+?5f-OC4pùh= ?3&فڎ?īJaݿ2GL"y 0Y]I8[�b NkLod8Uؖ ^!<1?&餻M=8w:dZܫcA?!9+]plwݕ"]}-߄A +\CNTj Z2ŸX^a>y ԗ4 Cj{f5>0plJ2V VӪg5Ͳt:~a||,R5!=`ti:3f$%ޗlqq;xЅҼJ] q8�"s `փJWa4dA_B1]?Ī?Mu!=g`rZ,r uy�դOaDE۵wX c]9SD+ŦdX![IDՃuo( J=!^˸ [sM8Ĕ�שU9nY�v1C5fy  s4`@Ay v!rerF\w7;`eq r5ں݀qq"cI7=͗B'$+/0uyHnPqlKuxqHS N8u`ɽE{ʓ` 2R(CfҺ\ȱ^d,L3HrFX�"zLTAND8;|Z{V6Gb٘dm.hAx-e|ɧ%+mؽOڔ.]iX'Qx&d-YXy{`xZS]2|+ۢ40m O%ol[haX_=3Gbs 4޺tz s!)H{amd?GO\B<} "q.2bȵmʠ?ZM[<lH!zǢT!mȡe  Pc,ٍ d^0hb '@<TUT#yI Sl`l[$l1Cn)6> PG49s?&1jO 4c.07l8TaTuZ\T؞D`F9U1U>Z#?tLH9CKn1I 1|@߭ٵތGM>_׆XE.!CĒTe*pb R^@2i)zeh3yǵFd^x 2FcϓӜpڔJjټkꕢMC_b 5Z9r;n切FgFbYdj'h#gSix”&wxxj4(Fsiy1yc!*Sa" ؙVb0R)^,38S%B1h<rO)gIO4'hnRm 8'UkW\9dpxnQ]Ch`f e-E*k"HSi?o5;A1+əJd2Z|] [tu=} i]CT T+J:d2*O<jԿgD5&;$LLun:j]bqso@~sq|QmG?ҢdXWQ",56>Gɭ[`%!6M(:B ] ;6VտczLGl(zq-mbA)ބh/ǯSs�3:֙XFKѹ(;ǸTC;RuǠa}mqRp[7YSM #ēy4�AfЩ=#ԍR(xCA@MȞL3rV}}#vFU8t41Ė&?MbPݸ<ηCsm~#]h>Pѫk! Y"{a[Ry6CzWcK#j VS3KjvZW"> ɗ~]h-{ M՚(K38FIzˈsk/+\HdR\|J4iqd|1P㐽Z1yZ\bm~/Pi䉟ȜhՒq̶&$~߽ؠTv5QlOg1R^@̈́,y/fӀ]$0 %-m~[7 Qu5Y5YM !K:m#Q[.*Yu˧1R-2o=;!%2j1"N #_o䶑7I8~@1Å}D&LwOs:Ч+G2Hi7[Y݃x lÿU$ECD¡u4Q99Tm>>w16ul~={I"k+q k3fٶOXGe 5$CS0wkW]Isc7Z6g%ޏ,ۤJ2c8x.Jy~MZPjE9絛V󴅚bEG*zy<;KPiFQXDV</\0)Q =Tm?Bw`. ,=ogg?l"UH(L[�;OC"E,N�5�l=~&E�+Ч5\ʙ>~[XF?")ua1%,A%`c6hfȆi0e6Z<OJ3Ҡl2TfSjγHOm) Cn*rqk6;Ga뀉:0ėٷW`PBBD~f"Ǭ:nuЕP !"yNV rxZ}Fݥy>xحmP;U{|/VwP7 3҈Y 7*-,\D8龬 $@@2?@K%69 O%LA"WVO쉥]Y'CBmUIL.#-e-# m3#. ~ ?qK1A,<2̝x8 mccNkܔp嶧RXan8T+{bkأ/#2U2۔gsZ[+/x q27{̛ P@cnPL lɸ2"d{0ü_06 *!vp) K{_K3YwؕK?y$顎X>F>/~`ynJtn@sT=Z_Ncj ,~. =BE!/d (?֙~bbR"} W C}|e:~Zd :g vd:W7 }th \}d>{1|zkυ}é}n#|4*g+Kmn/ENiYdj[n!R0@JjYKlF#O]S<%lQTht,t4n AtkC9vin#-}p-`ilPbGX;B禨jў( {y@l,).%ڪTElNωqE=!ҧ9j. b>w2�>@f9*h> Wmmi$g}PvûZx3 =sXɣ'WI$g |$Kg._1/ho_Qiх: yF[6ւFn4܌ {KBQeE}a̐R~H=q4D!n%pb7i&yź7nu[npf`漞0@hΏWM?4Fcz]M,t!?Ѯ f&l "�D툢J+\yR:O97TOggS��8j�����m���tNί -  !5""!/sErDc#$$$7  n8W(@J|)_ƋEd2\߼#F\~3G!CYVr,сߵY&pijeVo< +QV$|j1#ͬzMI3bڄJB@X;U6F0a#݅,-V]ï(-H9slw|idڏE>$ +|MeD$Jˌ7?6V:rh{\!O2Vt c#�bL|LUeT字hA8׻g]S9PxV3~8/ʆF/L>$ɟjcm(3@THFmCi%~-l>u*OI>̩z˻1Ayi?"xdš-7ğDS0$zҲ8ysQd>PXB\L1�V5:Пs6-:0/ikkWL<+AF]yMX הP� &0K#JpdN'[z!Q/ 3 ]z; wq.MZJSELF@9 T{S郁;`"WCĽ|VIQ^3Nw Dgv\ތ68wzFVYj~ Vf+n8ee(c;iGڧ'~[ϯ84&U$H+<1ЃW9: /]tWʻxa%WfۨDڪkWCne8%vp?c�*NkwQWrPh DlIsܸMRsU]i6 F6dc}K6;G;g B yg~=<w^VP{|TᴭOOگ4ԭ]]?2Wh1-")|1y@Cb-y9.1]#<�+G9lE4]{$ `)^{07ܢz/V2gaC4c@oV"Ξ1תE>C1Hh|vDw8.(Bh'>+*zc$l~yyYٝn`~^;j4~,kxظ2MǙN䍀HSqU#r科 Vlr8 +g\zn޼p"6P#LuLG_V30*.ʧx'pj˺OCP9ąň~cfa][?:tŜa\˔hF #Wv՛C ?ˤ`;m_v6"Xw"6{&Хµճz288cvt GXsZ8cXgju4bj۬JK6R"cmmB+1 /nJe{dzf֜0g:I�gm`YŅ/`A.^|\^0ƷDYZ~pҖM=h+ lwiS3F$y�PQwhZ85o.ʁ!x΁lLq(qV @$AM<kjIk8iL]tih0sgɂ_kit@J!#Hkisݢ*|iitph%U7\#ʗ1Mmm,Qw�#cHN׷i.q${4g`䀬!#StܵSJ<DDPw.f 6nP+s!S1%ۑ+qk8J[O#�K`.(&04oj~6q~ @,[16@kEW ՕY/S'l[yv#Y3lgY!Yy[4Kͬ&`c!keGbdHNjC$&a}UT&FVm,\| H>(ĸ ]ZKG\ 1:ZuK�^ko92-T> xeE ߁g_*|�q&;$T9E|0{~0hKM1<cW?qf]]曙KilA C23R_j_y݌ZBx>?IJ2u[j`Aw$^ZN8:)@icpej5,bL9d;}-PJore/V\wQЉYuT~]+dvob@e3o)We@v!D?]%y$^&7 H1K;ۭӛ/bNKW_< vZ=b$4h""ԧsKoIP٘| QN.T4 UQ n~]CDB,pTPA ySij[Rd�[ݩF @Q@HqNjhOx((:J c%Ho a;idrI'kj.vn 2N8iGiF7K4Wjאۭ코\~;#aBXk>Uu/PGz!PS6 jǮ%4놂-ԹТA7Bc*iJ|F,H`%p_1:_PofL"<w~g$.bMf׀J\;x6cp_(#e9bڳɰZc]0Mvb,$u|_dݨF1Ŋh*2˖{C˚~yw"xeź!wo@NٝUrG?* 2fbU+ ) tsm=*C:Yb߆8 tBVVx#^b\ԔEhE$@[/3wcMk(I~ՋF>�v:e~b~Ź=`Z�I SAܕ7Hʞ hi!Sڙi)h0z�wmmkQhb*]'Kl=xv0@e\K k1Bաc%qqN|Ѳ{K񫩋Ie/f ;Ǭ دBîk6_@0gM9COq7ڠ&sOČk=ۻ#[fH$7g@M]bYBCʐk8㝁2xUйZl@EAȺP'n-U<(<Q\y%NӃ ٦>f d4"!R؇ܴ&G]sPזA[q_fibh![w%:F!#NOEÓP>n�ۚ_|z&ǹɧ%k7j=U!VFR2 Y֝-+De`YV!'pg3q w<kEo9iz:�E`wT$_ϵ@Oóz{@E?RF fJcUPR_ %uY &@k?YD cm!341qNk:;MPtn$Ķ{s9&R ٍk?VU/:b3?hܼ1O)kPL_'Hl6w-!lvە7jQR=4fȱ&`Kӣq#iXS_oD4qșk>@wzj)[j9 ܤZHc%LUmYI|0wQ[?a+Hd2*cQ{wÓP# |i0TgevJcrvm%=ǀu00vUɀpA!TiLqUDm,qOS q't�#qh</d)zZdB c=64wS/d9L \|%57fA^5Y]`ިbvN 1_gr\pQ31 t<.x zd}1a,xAjh$Q%xIv4JKrlCTBx? ?zq-a)zG-OggS��@%�����m���huIյ !" . 5!!cBDCB˶#" ! paapq1/ !!AcdbitKz@. ynL'7y[Ý|4W8:nNXS[2b/JR)$QB i N=2+NI =BShj! &wX<._Ϣg7ZؽV@LG3O|<WvKPmmm4TcVp!$@phLv~|\E:neTAr�o,Z@R.ӷ殥3I'JP$Uz|(-sx`Gf#o:9h'jvPAfؘ롸8X륷)>¼ )o3-bt].j,e1_EOZ#ڝp:q^isx"�H&AtwfCjv5<%OxA#mO>v< S"o)<IQK{BvH 1NMlEfh+'XMh<0smR \:W<{1 -zQ$*C0ĬX&?Yi4n;gcU'>M:e F*k?�ن;\._bjW䂐qS ;[}sf!Ij`qEώa+uT<BmqJ|׋2"n:%zxr:qt�!3Mj!lQ EFp <y_e%J(Ȃg4*q/! ͶcgCMQq?^SChɗqNO2�QTÕc7c,pՆ]-S ִO;s{~ q*k MYyjpg&uǎb|g"[S'@QpOfC; I."KG�{\LMUKo ,iRD,7<$G6Ô[(fzcCބ�wcutfkg<S\c@"a_YphmͷA!jBXi3dfvv+SJV(J;k K_� ړ xbdX@sj&jf%F 1Qįd/RP 8tw2nw"AwxzG#r{+pz& kԢofXЊ͉_T+ѱ Q0o8{Vk *+2f`9Ce>L�a+A6WM}~CG_{q7d X'o+hv $i8}ߞ s/,k6YmCiX꺜ˆU־[z:%*;FR3Xwh'/34xֶah?>-VO~hXhx \\;^-ni_NG]zZXۧ?$fYZw`3 diҩvݏs'@既5@<.gUTn>BrdqV53=Wl*\x(n=i-F2%I:Z=J-hQz"K"N;+x#G#„D֐{v,ymӄe@t.+MS>(s 3&cc1Ws:%cD;:eb?&ȐޙA̠wWr \n1TxA`M� @a"r@_VQoƖeTW;+RO9gbuU׭ٰz޲nJҼ@ ]k�:z[CeUITn۴~)!TQ $K0[ȁ=5% q ܘ CYvg1eQ]Pl1.A�v݅'kތ;DB:;}jx̑mzyq,Q}bs}fFÒebXxO||<J(JnG8|ɴ'58 s_=W% l+xbrtYNr=>ؘDw[ [U:Yh #UgW<u9 aAKVX�71["twQ}rlM*v3ݭYa^k܂=L]SA lIBZ:P漎&G*`8 lr;4!4$il6*@_1锇:j,HigIH0M)Ԡw(܌OTGDyvu[sv3R8:E͟$5ahZI, 3nlAx+IfjkÀH^2(Rf0ryP_4�բ0\C\bjL~#,Lpf~P$=YoWᔸ"{*O@~t-80hx!\a m bYѰٴy3f3)!dC=ډ)|d c3F ƯDh6߉~l-(@YkflUd퓸R2vDjv8uLAoVcIHNO.ȏ;s jso, <9t)+!C9~CV{wཉS/o`e/P"oD >r[#*эEqhd~tA^7-M09|ˉ,G_|LHGOj*?[� ?#Kg'iP'ړ(4,djaQMQ Rw_??c#jki1mH/9HAAdӗZL'ښcf\z(0qId�S70~)4' =֤3g?ntq {_S`Sݹ6EWGލ6BI)XQl�7%P%6M" S`k{}9(?u/l덷z(BbvyƊaͽW3*JFDo071ծϔ8֤" Ϸ|#gq$*x[ % 0RGB k#2ZY7 R?nŷO3B9cL8%r%ׄgB//ǐ0 ?sX((L;?qD_§8`~Skfaē)g~+pLS*z=w9W职CXk-,5O`j5)v*JV={nQtHr5HqeVU@ZL.c^U{Ey3*}Ev^fu .*J|B^!MZRbmޅcY|P8OwS0�ǺD.k0FQE3q~{kI1_.)nD Djz#EOj/[=v$Sbiܛ{>]Q.V _jU&iƀ#Rg͉JNh{H6;i3-l�tjX2QwH-ۗ*/xɀ?M1</zîkQh. 9JB@)+4j94uBh]|:;a;ыS7e yVwq:] u9'7eZ$&f\#53+b`5SyQ-@E2_!RGErknisVYgB?GFNװ.AZyj`[lW!{0ihe,2?kHDw.Omh=P+)QisAGQh67ڇoh|@ߙơ~khCL3`B.kP~g2RI2v ޸w\hbY {+ij&KM}8+j¨.q8yOECq]4|0;": DV�Diy_M@auBȥjMD=sWc 7(�urY[gE:&Xa {o5S,\ ;A4q]H0[f>7"S.{U@‚"3[*r$4 H/ qqN@�`aĺJU POggS�������m ���V]Ap/ !. dftsvstscrBbpof"$""" cKeiedeithsduFf76""6"1#"$  pe$h0(/#~tT`*W!P"?G9Mb>W@蹻4TzM2n(KIL- Ǐ?3Ā@rO<Gu.41"(BYs/cl2 l;@@wioZzO{ـTH ɋW7̙/0ZKn)kb4|3iZH?f ۢuy=Fio m;275w;̼tiTi$c@>NrusXFVM ~)K1XCCuI<a6bWϩ;=<_kJbG isr1y�qi1SVrZ4qgI2uFĀpk<E~'n6;9Z>bhI6GzcٶIqڵpsjXiL-bud9�ŧ*Jte\rI $gwld-<: )'`EC 'g*{:"$;Fb,j+5xp&h+`hmAupp<lD�फ़E12߆|4cwDq"VA {pOٸWԜ:<ʷu]vIzF�BixgPTЫ9XpukpkGo[,J:wʪ Ô).8>_[ofn :h2] żc_ߖH>{``jEZ# ĜRz叧ok gN-@rUǾ1 ZN7KoU~3sx]Z`sVB4|Fd3|ۑۅrň4xl K J\s f9p4xC'(EH$L@=1)?<FfĶ�8jOzWwF$ +wE X/Jk]ƖT^p3<HAbǠ?\HԟAMX397­5JDF�Pz,'gAIAC.ML.@~&}|x9fANZɊ�Lqju  B!�,_<`N؁BAؒ5ۍ}DyDPXV5Vç(N[Q<~*iN~IR ~a 疤M7Wҡa~^2>!S.LJ_VH.JZLMKSX:?1 %n�/kÜH ߋf1 L5deFWriP|u@#x"O N&I2R$g> dSܯ8X  4Y *vuaDf`>.zcZ~V(X)H~L E Z"hn0BKGܿinܰ BL)RAY\in' k?s²Lԇ/k6X!g$C!E:b<-D.W>9>OZY,=Цd@41yfw4B#bIPLGc-Q2 bs~v"S1yVnagCzv uNNxPłnxgxX(C dmVٶrn7@~îJ9w7aCS)D擀CC~ thtT$bV{tlA%]sg덱HZ|&uq=FC.F@8AIYhZ5wA[(~ 8=88xrz8lWg~~-⟯4#RGl7p/// jdždOGDفݛ K@944jNlf&h q+3y*`ȐFt'~UKPS;Xu.,<^ަ,@f= 7ɟ%.M8/5VFZ^zbtWck؟AևЯ՗bTjJg\jeF?H-eOlWZ}Q}tsU 47!gw ,0(o> $41!h1xa k0�j=@2* }ό sBpq kG�BV3Z"{6K=I4>{fT_{(j}g{;y"ewB ۀ{@aڀ{We6|061}ȥ(qƍQy̶-By'M;�wTcey:qYj{sB{"QyJ́@l$"o$ȷ"ӨRs &XzHb;tp,Sȍ'gF`ݣ =  jcM]%mU|';b\ϩG�I: ʬqn%JekIqK>IVn.$*yM Jl !ൔT]<HUoOPG4;w?RY}%;PkZLM8*̣B&~0hfVmm%XoϯFyiA2;Wڿ`YE- W+_*9VUxpRtx,py/ ,2$�{9 1C֞mm-zRWc1w:-5|pisn<�sILA5z؃W &S:jBi3IKn/mR9/Y2[}0!kw{&FyAl �oeq@H"2q;a6lϏ8 ]Y)ÈwФn^ Մ?BDНvRեV^ۛfL4Xt|wqosJU6DvP~<'[D{*/hd0K~oub7h@6ʝR`cVs.=0s (DɉOz?m3bETp!L[0XN_ PVty⧯~Y/o2ҙ.7ti)V+ h&U`1UůbDE?׋o)|x!019l@'E,upd|vƩ]-C_H8O0J$I/] :L�(SͼD`P/kG]G`br&z?^2Fd׼F}Pv3Ujup½b43\>2& q! N( Ɓ!7j:l!sn}pZH!:OdK%�BzJ4qβ d<fq}* X/J\ ~^JEO')۵ZF=]p %`gER4~ )˯_Z"� t<Ӫ)4B&U~O[s>^0F67܈pSҐ@] ӯ/EqI~|Z 3LHY[iN 2g^ ݾIO>McCS:}q޿]~ [~5|ȴT6). hP�쾅:RFtޗ^W!T`> O[FSutYxPbݭg`G1Lo|>o3oH3H#! J$r+K e>,/ew]5׊[h3T~gR~[$@92"ZRp~YJs)Ĉ$HrU81;eR:jKUMAbNb*!bx/ -㭵'6�1 ֵ0G~B;=fJ7F)}&o>#!!r(7KhJh:|,4UјYz_!mZMjjlA.zGۈnv覔x(/i1#jp0O$6Y9"II"Yt)ghu64N�R(HKcZQyKx,tjn[;;etn'}3@Rfϗv.*麘[{)wU)|T5ȷjjw ud�VӨbے3"rH"dG~fol wp9=4+`ݞ)d*IXTɡl}Gh~�_65yn«Iܨb J|9吻U|4(�tmp 3뽲PQ{�lpA,?BleOu&}+B1qq] R'><V<g�D wDh(E7wJ°d>?OaqN1@Usb|΃I$u5ƧZ\rv,OggS�������m ���HŲ{IcdsE Dpudd"//""fFgut!7 1" .655 nqpp`hMvMu|�cF[&j@ѐEn[{GPufiSM8FKhR-H0__F\rhGv:A9?"}^�qFTLKì]t`Qy삯Z@Uh?m)VSafǂiyl|a&kJ-+;5| �:Ӫ(e 6 &T]aj]fhZxY]ցCf3;Gib ov'98Bg+,gϵנh: ~g+N|o -'?L sSzBݘZ3qY5v(RVk }1z X%Sz/Xwy20,2wP6wm`[z\x \NR׀sϤU1Pz޲'wzx4rY.<JOzIDxOz[$Jswu3f{enxEuiHDBP]]11HqmkU@E`mꣲ@E/j~RDɘC@ mI$;OfdsshR.T"i\hV>R ,eOS:Rri@;~7o)~j- @>}"D 6];\f7H^~~4!%v7ni@yOk 2+6b*:ôxo5sZ󂿣F1/#W=[@bS3 E^w0buM<v# dW\p5-n &p35BϧS%el9܁24fvd9y/X G톜6$RnWh/HfAXфƷڿ{UX%IOy;~88v- 1I-UBimlMic* b7HqQKo}efFjxqNܡ|;,-[DsFn1,)BDk�J;&M$�Í^~X9s]X]jXjUm y2EA>W:xl}Xm`?@4`"3z͠wj3P^O`B120ruRm{2Q-}Tm[&ج#e*V z" D ?F/]+ Iyz)z 4v .၈j~n _=ZygȆMw8Rt+2ѳzxԔ]W 2\/hEchёؿ!<6{sUPCWx}Rl,~ p^.ܡ3R52i{wF#4cq"+ȜvC-ȟwJM\ΌUyZ'm^ԤBhM'%$#߾KCdk8 rP }H*0xQ=$ q󘥩t/uZڑ}')(j%w؏\[�~p@]# EZжO7&\QU- V0%Me6>L[|3c̮k0$Z[ 0jq@$.EkĻAJ}1tm/qeסE@a}a6]>?S~qO+q/6-W&Ou> ;g0QnpKe>pچ$~)ԙ8X;!.?@b6ves0IAՓ fyjL�is:EbVd`_]J/Α=Fdd$5#`t5iKY< ">+}vh'%ˢַ۴1qZҫ߽ϊ v7(ؒrlc#Fd!,mP qH.e~Ի*tv2i?~od:Rt22;mnHo~'1:ذ:)n k`;g.01 | B{uS` i%RGt1݇+Ie'3ɽRG ([i"m K/!~fj>r*pz6ρ=R[CiHYز׃=! ae45kA5:h1u':On~YD2;39 <lߊ=2Q�BR ;dҪw1DKa-6ދF|D N!duu+<oxې#~LF(Dı*i"(=\7 لYZÂzS�vA{Sn8#9t]-mRstvǣ:fO)o)Uz,Ш.>`5Ⱥdcc@rTHY!X++%eNɠQTI)kbRu#\ώ)JZs{y챬6b~^ۡW tU~7c=N~ 0a&x~nvt|ʳ_zZ:<;5xM7Ww Y,ez&^IRS?fT$;k㉫Xo~[XpE˘1 Yhƚh5pL0ﰶ#E֤]((y5_0aO $H 2Б1tqѷlsXA.;="HkÁ'=E#~[QU+;橊!EDki΍{ޔyf{#3[TJBXJr' &3Lbb.) T:hbo~j/*5^Ot"'Fk!hw[W m-e'G{D*BXFhc޸;v!7d N~s Ye�cŖWQT>19uZ)hj~tvHfz u֥8{ o0ZM>(W~A}*ەMkoOvوlb^t҅h ~rNjQ7AVn0?䟁4/gn@fy{G}E~h:c} )'%9γǖᝲ{/Wa[D}'2!iEϻCT˩G*as3hcb,]:W2d:Nmx3*EX3m5&}Wn&FhGY2.JvI@As}&ŀsd0]s48w AR~]gXǣ!L̵Nvon 1.)AĔ8ƤȀ'&� K{ ^bL̕D2Bs3ț1e:P2߸szz(MJ~ ꏊ ` 7'7׀arGM؝z唦;ϔ$}A{O"j-Ʊ/yRk|J䟒gA50TLb.H@NBS̉(dq5;M׏e~N@"s$>\o8 Ho91{ܘSNjh<zy@? tUAA7GlG4Dwމ tnz!kr@c ꀲ{ x-D[G(?ۡR¤AQuقVvlP*:qY/ h< |ZCˆ"fȄ 4L{%Tu 3z\إ|$Qn.2 csGECOW�VA É ˠ g#p;oT!5śYu+Va*pUPFĭx՝J_L �@ob1zፃ|X}SbpNլvbߨ3hTK ;헂=$ҪE6n+:1&Y(I y8hU)0agJ FÞr<,E01L#*vnt6&j'E|+8&n�xkR4#́Bmp>|P[ ~Y (!gj%K3ɮ`+?q4o_һ}LF9|9oROv]w>ܩZ 6^(zj T/qH]2m`u)�>ŎXxBdۭϝMڽZpZ5FQEn3VLbځ[М%Ky'}^53f:'_^\YKU<U.Ns1ߩ]70@63!>/D#fu[ɑ/i9 AMօ9wn&9$/7bh4�7A^qDoaQLa^p_bb�kb7W3?'7 w/0$PL-Vo c>7QJtWBc+ԧ:w q=b/-P rRfwڕ f(Ԥj1C]%샵$:3tOggS�!�����m ���˵hxmCamcob2tJΚQ XO?' H 2Ra5GbEP|> Hic>䪁9\*zF-D ?a-!robkv<w.@�.uQ#P$_* 6P1h!/F҉}P{eV2v[ƀ@G ?Κ|v7~];D>aZBT=a|I35+emV)�i#_Q+kKQO$"K"HɒUU>:u9PlNV:'VD(a)N&E@xm{(zˋD (4/]jfVyOHCoFlN#걬V%w4w@z'BiMq3 %srd4bVIۭGELXA# )&ʼn##OWo#^)U3$,hڙ"YEZsӢ7>3򛦩z`tqEۢ32|.Ksf>45nAW ?F����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/covr-junk.m4a���������������������������������������������������������������0000664�0000000�0000000�00000011764�12225024651�0017370�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������ftypmp42����mp42isom��mdat��libfaac 1.24��B� 2�G!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#��#moov���lmvhd����ELII�_���������������������������������������������@���������������������������������iods�����O��ttrak���\tkhd���ELII�����������������������������������������������������@�������������mdia��� mdhd����ELII��D�~�������!hdlr��������soun���������������minf���smhd�����������$dinf���dref���������� url �����stbl���gstsd����������Wmp4a���������������������D�����3esds����"���@���� �� b��� stts��������������������stsz����������������� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ���(stsc�������������,��������������� stco���������� ����I����� ctts���������������������� #udta�� meta�������!hdlr��������mdirappl�����������ilst���----���mean����com.apple.iTunes���name����iTunNORM���jdata������� 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000��covr���_data�������PNG  ��� IHDR���������Ԛs���IDATxc|�� Xo����IENDB`��/data��� �����JFIF��d�d���C�    "##! %*5-%'2( .?/279<<<$-BFA:F5;<9�C  9& &99999999999999999999999999999999999999999999999999���"�������������������������������������������������������������������� ��?����name�����������#ART���data�������Test Artist���!too���data�������FAAC 1.24��Zfree������������taglib-1.9.1/tests/data/empty.aiff������������������������������������������������������������������0000664�0000000�0000000�00000013460�12225024651�0017027�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������FORM��(AIFFCOMM������ }�@D������SSND�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� �������������������������������������������������������������������������������������������������������������������������������������TEST��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/empty.ogg�������������������������������������������������������������������0000664�0000000�0000000�00000010350�12225024651�0016671�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS���������ۿ;����Zfvorbis����D�����������OggS����������ۿ;���r-vorbis���Xiph.Org libVorbis I 20050304����vorbis%BCV�@��$s*FsBPBkBL2L[%s!B[(АU��@��AxA!%=X'=!9xiA!B!B!E9h'A08 8E9X'A B9!$5HP9,(05(0ԃ BI5gAxiA!$AHAFAX9A*9 4d���((  ���@Qqɑɱ  Y�����HHH$Y%Y%Y扪,˲,˲,2 �H��PQ Eq Y�d��8Xh爎�����4CS<GDTU׶m۶m۶m۶m۶m[e Y�@��if0BCV���0ĀАU��@��J 9ߜYJ9Hy9s19眢Y 9ĠY 9'yК*9q`9&y9iK9HyRK9s9s99眨9Oޜ9s9s9 4d���@a)h Fb2A0 Bh:%qRJ' Y���@!RH!RH!b!r)J*2,2,:쬳; 1C+RSm5Xk9皃VZkRJ)R BCV� ��BdQH!b)r *АU�� �����O%Q%Q-25SEUueזuY}[؅]}}uaXeYeYeYeYeY 4d���� BH!RH)s9$ Y������pGqɑI$K$,O4O=QE4U]Q7mQ6e5]S6]UVmWm[uۗe}}}}}]BCV���:#)")8$I@h*�@�@��(8$I%igy陞*@h*���@������xxx舒h+ʦ캮뺮뺮뺮뺮뺮뺮뺮뺮뺮뺮뺮 �$��t$Gr$GR$ER$GrАU� ���1$Er,4O4O==SEWtАU�� ������� ɰM%R-US-RESUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUM4M Y ��S--ƚ $bjc R쥱H*g1^Q{$cA-)&TBc*RR 4d�p@,@,�������4 <4�������$M,O4�������������������������������������������������������������������@4@<@<�������<<D�������,4<Q�������������������������������������������������������������������@4@<@<�������<D<�������,<Q<������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������`!"��pH$ HM4eAӠi0M����������$MA �IӠi4"����������AӠiEi4hD����������4!E&3M"D ������������������������p��0 "��p8e�8��X��X%��`Y(������������������������������������������������������������������p��0 ��p(eDZ,8$ɲ�<D���(p��ASbqBCV�Q��ű,MEi'$I<Oiyi<4!hEQ4Mi*0MU��P��`��B�bYy'$I<OE4MSUIy(i,M<QETUUy(i<OE4Uuy'hEQ4MTMUu] i DOMSU]u牢i.MTUUu]Yi2@UUu]W뺲 PUu]Ye�뺲,����*ф @!+(��S0&!$B&%R RR)TJ*%Rj)UR) B*%R��؁�؁PhJ� �0F)sN"c9'R1眓J1sI)s9礔9sRJs9)s9眔RJsNJ)%A'9��T��`#A�R� cYyh$iy(&Iy'<OE4Uy(i*E4MUU],i0MTUu]i.l[UUue꺲 \ueٖ,ڲ���VG8) ,4d%��@B!eB !R ��p��0 �H��Zk@gZkZkZkZkRkZkZkZkZkZkZkZkZkZkZk-RJ)RJ)RJ)RJ�U8�?ذ:IX`!+p��s B)T1tTZB1$ZlsA(!b,sB))VcQ)RRJ-XJRJX1ZbI)Z1#lMjck*-c_dl-j #[,-Zk0[1>R,1\��w�D3$� � R1s9R9sBT1ƜsB!1sB!RJƜsB!RsB!J)sB!B)B!J(B!BB!RB(!R!B)%R !RBRJ)BRJ)J %R))J!RJJ)TJ J)%RJ!J)��8��A'Ua BCV�d��R)-E"KFsPZr RͩR $1T2B BuL)-BrKs���A���3��stG� DfDBpxP S@bB.�TX\]\@.!!A,pox N)*u ����� ���\�adhlptx|������|��$%@DD4s !"#$������ ���������OggS�z�����ۿ;���f}[� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/empty.spx�������������������������������������������������������������������0000664�0000000�0000000�00000057355�12225024651�0016747�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS���������'����ǑrPSpeex 1.1.12�����������������P���D��������������������������������OggS����������'���[0!���Encoded with Speex 1.1.12����OggS��n������'���+-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]tN��mC�_mm/mmmmUՅ]]]]XUՅ]]]]\ֵtNkmE_mm�/mmomUՅ]]]]XUՅ]]]]\ֵtN��mW�_mm/mmܡm%UՅ]]]]XUՅ]]]]\ֵtNFS_mm�/mmwUՅ]]]]XUՅ]]]]\ֵtNq�m`3_?%/mm�mmUՅ]]]]XUՅ]]]]\ֵtNa�m}�_mmcmҵ0?omUՅ]]]]XUՅ]]]]\ֵtN<m�_mm/mmmUՅ]]]]XUՅ]]]]\ֵtN�mP_mm@/mmhUՅ]]]]XUՅ]]]]\ֵtN(խa_'@mmUՅ]]]]XUՅ]]]]\ֵtN�m}�_mmثtbmmUՅ]]]]XUՅ]]]]\ֵtN(mmB_jȯmmsmUՅ]]]]XUՅ]]]]\ֵtN@�ma_o/mm[AmUՅ]]]]XUՅ]]]]\ֵtN�mn�_mm/mmUՅ]]]]XUՅ]]]]\ֵtN_"mt"_jVm mmUՅ]]]]XUՅ]]]]\ֵtN,�mj�_mm/mmo5UՅ]]]]XUՅ]]]]\ֵtN�m^c_m@/mm(m[mUՅ]]]]XUՅ]]]]\ֵtN_Dg,_mUՅ]]]]XUՅ]]]]\ֵtNpm]_m/mg8տoUՅ]]]]XUՅ]]]]\ֵtNZ�md#_m/mm#mUՅ]]]]XUՅ]]]]\ֵtND+^�_mm+ m`mmUՅ]]]]XUՅ]]]]\ֵtN;�mk_mmٯmO#omUՅ]]]]XUՅ]]]]\ֵtN.�m~#_'mfmUՅ]]]]XUՅ]]]]\ֵtNPj�_mm�/mmrWڵ5UՅ]]]]XUՅ]]]]\ֵtN/ƀ_mm@/mm۠mmUՅ]]]]XUՅ]]]]\ֵtNt�mx�_mm/mmUՅ]]]]XUՅ]]]]\ֵtN1�mk_mm/mmѠmmUՅ]]]]XUՅ]]]]\ֵtN[�m@_[m/mmڎmUՅ]]]]XUՅ]]]]\ֵtNmFmR_mm/mmޔmUՅ]]]]XUՅ]]]]\ֵtN'�mW"_mm@/mmmUՅ]]]]XUՅ]]]]\ֵtNFm#_m/mmUՅ]]]]XUՅ]]]]\ֵtNC�mu_mm/mmXmmUՅ]]]]XUՅ]]]]\ֵtNm\�_mm@/mmmmUՅ]]]]XUՅ]]]]\ֵtNrp�_mm/mmmmUՅ]]]]XUՅ]]]]\ֵtNcmOʀ_mmm@mmUՅ]]]]XUՅ]]]]\ֵtN5�m_mmA/mРmmUՅ]]]]XUՅ]]]]\ֵtN8�mu_/mmLmmUՅ]]]]XUՅ]]]]\ֵtNz�mR_o@/mm�mmUՅ]]]]XUՅ]]]]\ֵtNPc�mU_�/mumUՅ]]]]XUՅ]]]]\ֵtN �j�_mmfm$OhUՅ]]]]XUՅ]]]]\ֵtNY�mV_m/mmߋoUՅ]]]]XUՅ]]]]\ֵtN�mp_mm˯mkmUՅ]]]]XUՅ]]]]\ֵtN(mU�_mm/mm�mmUՅ]]]]XUՅ]]]]\ֵtNq:kH�_mm/mmܠmmUՅ]]]]XUՅ]]]]\ֵtNp�mI_lm/mm mmUՅ]]]]XUՅ]]]]\ֵtNZ�mq_?m'/mmcomUՅ]]]]XUՅ]]]]\ֵOggS��������'���B-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]tNH�mi#_@/mm`mmUՅ]]]]XUՅ]]]]\ֵtNP^ԿZQS_mgpmUՅ]]]]XUՅ]]]]\ֵtN1�ma_ikAUՅ]]]]XUՅ]]]]\ֵtN_oڵ@/mm mmUՅ]]]]XUՅ]]]]\ֵtNH�mv_mm@/mmҞlmUՅ]]]]XUՅ]]]]\ֵtN��mc_oow�/mހmmUՅ]]]]XUՅ]]]]\ֵtNK�mr__mۅmmmmUՅ]]]]XUՅ]]]]\ֵtNk�mj_mm�/mmmmUՅ]]]]XUՅ]]]]\ֵtNp_mm�/mm`mmUՅ]]]]XUՅ]]]]\ֵtNbI#_m/ٱWmmUՅ]]]]XUՅ]]]]\ֵtN+.O�_mmu/m mmUՅ]]]]XUՅ]]]]\ֵtN7�ms_mm@/mmԎ%[mUՅ]]]]XUՅ]]]]\ֵtNԛ_mo@/mm`mmUՅ]]]]XUՅ]]]]\ֵtNfηz_mm/mmޠmmUՅ]]]]XUՅ]]]]\ֵtN{_[m/dm mmUՅ]]]]XUՅ]]]]\ֵtN_�mb�_mm mmkmUՅ]]]]XUՅ]]]]\ֵtNE�mT_mjҿmJmmUՅ]]]]XUՅ]]]]\ֵtNsFs_mm/_mUՅ]]]]XUՅ]]]]\ֵtN*ԿR_mm"mm×UՅ]]]]XUՅ]]]]\ֵtN�mp_z'YmӬ5oUՅ]]]]XUՅ]]]]\ֵtN=�mq�_mm/mm߀mmUՅ]]]]XUՅ]]]]\ֵtNwmE_mm/mӭmmUՅ]]]]XUՅ]]]]\ֵtN<Xֶo_mkmUՅ]]]]XUՅ]]]]\ֵtN0jx_oѬ[텝UՅ]]]]XUՅ]]]]\ֵtN>�mo_mom:mUՅ]]]]XUՅ]]]]\ֵtNP`Կm~_omoUՅ]]]]XUՅ]]]]\ֵtN�m[�_mm@/mmmmUՅ]]]]XUՅ]]]]\ֵtNfη]�_mm2/m|Ӄ'UՅ]]]]XUՅ]]]]\ֵtN'�mq_mm@/mm٠mmUՅ]]]]XUՅ]]]]\ֵtNmX+_m[m�/mm@mmUՅ]]]]XUՅ]]]]\ֵtNb�m~�_mm/mmҗ[mmUՅ]]]]XUՅ]]]]\ֵtN�m[�_mm/mm�mmUՅ]]]]XUՅ]]]]\ֵtN �mZ_F/mm`mmUՅ]]]]XUՅ]]]]\ֵtNT,v_@/mm܀mmUՅ]]]]XUՅ]]]]\ֵtNtFO_mmmmUՅ]]]]XUՅ]]]]\ֵtN8οmp_ummUՅ]]]]XUՅ]]]]\ֵtN&_mm/mmmmUՅ]]]]XUՅ]]]]\ֵtNmOO_mm@/mm�mmUՅ]]]]XUՅ]]]]\ֵtN3mՐ3_m/mm`mmUՅ]]]]XUՅ]]]]\ֵtNl�mJ_m[m/mmՏUՅ]]]]XUՅ]]]]\ֵtNQ�m}�_mm�/mm[mmUՅ]]]]XUՅ]]]]\ֵtN�mo_mm`mmUՅ]]]]XUՅ]]]]\ֵtNJTӶS_ml @/mڀmmUՅ]]]]XUՅ]]]]\ֵtN~�mw_mmMmmmUՅ]]]]XUՅ]]]]\ֵtN2UI�_mm/mm,[m[mUՅ]]]]XUՅ]]]]\ֵOggS��O�����'���r&:-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]tN mp#_mo/mm׳mmUՅ]]]]XUՅ]]]]\ֵtNB�mv�_mm/}WmmUՅ]]]]XUՅ]]]]\ֵtN'Կmp_m�/mm۠mmUՅ]]]]XUՅ]]]]\ֵtNpm~Vmm/mm@mmUՅ]]]]XUՅ]]]]\ֵtNP�mn�_mmCdmmmUՅ]]]]XUՅ]]]]\ֵtN7�mq�_mmomխmmUՅ]]]]XUՅ]]]]\ֵtN:Կ{�_mmѠmmUՅ]]]]XUՅ]]]]\ֵtNP\�moO_m3UՅ]]]]XUՅ]]]]\ֵtNvF؀_mm/kMmmUՅ]]]]XUՅ]]]]\ֵtN=Xm_mmݠmmUՅ]]]]XUՅ]]]]\ֵtN$�mi�_mm/mmѠomUՅ]]]]XUՅ]]]]\ֵtN/ _mmGm mmUՅ]]]]XUՅ]]]]\ֵtNv�mh�_mmomUՅ]]]]XUՅ]]]]\ֵtN*�mz_o/mmmmUՅ]]]]XUՅ]]]]\ֵtNh�mx?_m/mm mmUՅ]]]]XUՅ]]]]\ֵtNc�mJ_m[mg/ZmmUՅ]]]]XUՅ]]]]\ֵtNNmq_/UՅ]]]]XUՅ]]]]\ֵtNq�md_mm@/mm mmUՅ]]]]XUՅ]]]]\ֵtNukR_M�mmUՅ]]]]XUՅ]]]]\ֵtNk�ms_o/mm mmUՅ]]]]XUՅ]]]]\ֵtN{Կ_mm0/m[ mPmmUՅ]]]]XUՅ]]]]\ֵtN1�mn�_mm/mmї[mUՅ]]]]XUՅ]]]]\ֵtNFm[_/mlmUՅ]]]]XUՅ]]]]\ֵtN'�my_o@/mmPUՅ]]]]XUՅ]]]]\ֵtNrFKX_mm/mmm5UՅ]]]]XUՅ]]]]\ֵtN�mQ�_mmu/m;ͿmۅUՅ]]]]XUՅ]]]]\ֵtNԿmN�_mm/mmݠmmUՅ]]]]XUՅ]]]]\ֵtN �mE_lo�/mm׈mmUՅ]]]]XUՅ]]]]\ֵtNymi_?/ym֐oUUՅ]]]]XUՅ]]]]\ֵtNƿӚ�_mmٯNmUՅ]]]]XUՅ]]]]\ֵtN8 dg�_mmm٠mmUՅ]]]]XUՅ]]]]\ֵtNP9ԿO_mmj[mUՅ]]]]XUՅ]]]]\ֵtNyƿ|�_mm@/mm@mUՅ]]]]XUՅ]]]]\ֵtNNً_mm/mmڨo4mUՅ]]]]XUՅ]]]]\ֵtNfJE_mmkm۠mmUՅ]]]]XUՅ]]]]\ֵtNR�m~_2[mٯmkm@mmUՅ]]]]XUՅ]]]]\ֵtN@�mu�_mm/mm_mڵUՅ]]]]XUՅ]]]]\ֵtNu>ˀ_mm/mmmmUՅ]]]]XUՅ]]]]\ֵtN�m@_mmͯmdmmUՅ]]]]XUՅ]]]]\ֵtNC�mj"_m/mm mmUՅ]]]]XUՅ]]]]\ֵtNl�mzH_mmmmUՅ]]]]XUՅ]]]]\ֵtNG�m\#_m/mmmmUՅ]]]]XUՅ]]]]\ֵtN&οm�_mm�/mmmmUՅ]]]]XUՅ]]]]\ֵtN9mkN~_mmUՅ]]]]XUՅ]]]]\ֵtNs�mn_omڗ/RmmUՅ]]]]XUՅ]]]]\ֵOggS�������'���ț-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]tN=�mr_mmm+sUՅ]]]]XUՅ]]]]\ֵtN/�mm�_mm/mmmڵUՅ]]]]XUՅ]]]]\ֵtN�_mm/mmzmmUՅ]]]]XUՅ]]]]\ֵtN)�me*_ڴmM mmUՅ]]]]XUՅ]]]]\ֵtN#�mg_mm@/mm7mUՅ]]]]XUՅ]]]]\ֵtN2Կm_oڗm@/mm]UՅ]]]]XUՅ]]]]\ֵtNԿmQ_m)m`mmUՅ]]]]XUՅ]]]]\ֵtN=d_mm/mmo[mUՅ]]]]XUՅ]]]]\ֵtN"�mTc_mmQ@mmUՅ]]]]XUՅ]]]]\ֵtNb�mx_m_G/m`mmUՅ]]]]XUՅ]]]]\ֵtNJ�ms�_mmHmm!տUՅ]]]]XUՅ]]]]\ֵtN�m_�_mm/mmoڕUՅ]]]]XUՅ]]]]\ֵtNF][_m/mmvmUՅ]]]]XUՅ]]]]\ֵtNP�moj_m@/mmHUՅ]]]]XUՅ]]]]\ֵtNI o#_/mmCUՅ]]]]XUՅ]]]]\ֵtNzԿ^_/UՅ]]]]XUՅ]]]]\ֵtN�mX�_mm�/mmߠmmUՅ]]]]XUՅ]]]]\ֵtN.�mI_vm@/mm׿o7mUՅ]]]]XUՅ]]]]\ֵtN �Y�_mm@/mmޗ?UՅ]]]]XUՅ]]]]\ֵtNƿmH_mm}/mmmmUՅ]]]]XUՅ]]]]\ֵtN �mx,_oo:/mӠmmUՅ]]]]XUՅ]]]]\ֵtNC�mh_mmCZHmmUՅ]]]]XUՅ]]]]\ֵtN5ֶm_6m!/Ƿm͝UՅ]]]]XUՅ]]]]\ֵtN9�T�_mm@/mm mmUՅ]]]]XUՅ]]]]\ֵtNo�m@\%@/mm#oUՅ]]]]XUՅ]]]]\ֵtNj�mn�_mmׯmmѠmmUՅ]]]]XUՅ]]]]\ֵtN5�m}_mQm mmUՅ]]]]XUՅ]]]]\ֵtN`_mm/mm�mmUՅ]]]]XUՅ]]]]\ֵtNxI_mm!/momUՅ]]]]XUՅ]]]]\ֵtNW_mmٯmmmmUՅ]]]]XUՅ]]]]\ֵtNBԿO_o5@/mm֠mmUՅ]]]]XUՅ]]]]\ֵtNu6V�_mm@/mm'mUՅ]]]]XUՅ]]]]\ֵtN#㏀_mm�/mm�mmUՅ]]]]XUՅ]]]]\ֵtNi�mR_mm:@mmUՅ]]]]XUՅ]]]]\ֵtN:VB_mۯp WmUՅ]]]]XUՅ]]]]\ֵtN@ֿ_m�/mm,mUՅ]]]]XUՅ]]]]\ֵtN&6_Vm/mmܐUՅ]]]]XUՅ]]]]\ֵtNPX�m\_j呯hUՅ]]]]XUՅ]]]]\ֵtNdοV�_mm/mm`mmUՅ]]]]XUՅ]]]]\ֵtN_m H_/mm݀mmUՅ]]]]XUՅ]]]]\ֵtN|Os m|S_6m@/mmڗmmUՅ]]]]XUՅ]]]]\ֵtNP�ml_Q[mK`[mUՅ]]]]XUՅ]]]]\ֵtN�m\�_mm/mmmmUՅ]]]]XUՅ]]]]\ֵtNwmOʀ_mm/mm`mmUՅ]]]]XUՅ]]]]\ֵtNs�mE_mm@/mmmUՅ]]]]XUՅ]]]]\ֵOggS��0�����'���m,-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]tN�mh_mm/ҶmmUՅ]]]]XUՅ]]]]\ֵtN>�mz~_o@/mmUՅ]]]]XUՅ]]]]\ֵtND,_m/mlmmUՅ]]]]XUՅ]]]]\ֵtN%F#_/mmԀmmUՅ]]]]XUՅ]]]]\ֵtNS�mI_/mmmUՅ]]]]XUՅ]]]]\ֵtNL�m{_mmkm-@ mmUՅ]]]]XUՅ]]]]\ֵtN�ma_mm@/mmҗ[mmUՅ]]]]XUՅ]]]]\ֵtN,~܀_mm@/mmmmUՅ]]]]XUՅ]]]]\ֵtNcoƀ_mm/mmzomUՅ]]]]XUՅ]]]]\ֵtNm�ma_mm/mUՅ]]]]XUՅ]]]]\ֵtN8�mp�_mm/mmހmmUՅ]]]]XUՅ]]]]\ֵtN|mY#_mڵ1mmUՅ]]]]XUՅ]]]]\ֵtNgfZ_jbگmmUՅ]]]]XUՅ]]]]\ֵtN�m~,_/mmmmUՅ]]]]XUՅ]]]]\ֵtNgS_mo*ȯmmUՅ]]]]XUՅ]]]]\ֵtNE�mx�_mmQ/խa?mUՅ]]]]XUՅ]]]]\ֵtN'�mi�_mm/mmܗmmUՅ]]]]XUՅ]]]]\ֵtN�mO�_mm/mm@mmUՅ]]]]XUՅ]]]]\ֵtNmO,_om/ZUՅ]]]]XUՅ]]]]\ֵtNX�mu�_mmmHooUՅ]]]]XUՅ]]]]\ֵtNO_m`mmUՅ]]]]XUՅ]]]]\ֵtNgO[_joA+mmUՅ]]]]XUՅ]]]]\ֵtN(ԿmH_mm@/mmmmUՅ]]]]XUՅ]]]]\ֵtN �mT_멿m`mmUՅ]]]]XUՅ]]]]\ֵtNBm�_mm@/mmmmUՅ]]]]XUՅ]]]]\ֵtN}GVmm/mmڨmvmUՅ]]]]XUՅ]]]]\ֵtNj�mU_mmm`mmUՅ]]]]XUՅ]]]]\ֵtN"�mh_mm/mmW[omUՅ]]]]XUՅ]]]]\ֵtNFm �_mm/VmmUՅ]]]]XUՅ]]]]\ֵtNMX�_mm/mmmmUՅ]]]]XUՅ]]]]\ֵtNr�mu_mڵ/mmUՅ]]]]XUՅ]]]]\ֵtN)mx_mm/mmUՅ]]]]XUՅ]]]]\ֵtN�mb�_mm/Ӣm%UՅ]]]]XUՅ]]]]\ֵtNƿVƣ_/mmڀmmUՅ]]]]XUՅ]]]]\ֵtN|�mc_om/moUՅ]]]]XUՅ]]]]\ֵtNJm_mmѯmmmUՅ]]]]XUՅ]]]]\ֵtNCƿcE_mmζommUՅ]]]]XUՅ]]]]\ֵtN.�ms_m/mmڠmmUՅ]]]]XUՅ]]]]\ֵtNaܿ γ_oo5�/mmԀmmUՅ]]]]XUՅ]]]]\ֵtNI�m�_mm/mm?mmUՅ]]]]XUՅ]]]]\ֵtN<m՞_mm)m mڏmUՅ]]]]XUՅ]]]]\ֵtNNX`S_mڴٯ-ٿ@mmUՅ]]]]XUՅ]]]]\ֵtNW_mQp mmUՅ]]]]XUՅ]]]]\ֵtNdF_mmf/ ڵUՅ]]]]XUՅ]]]]\ֵtN~mb_n�/mm׀mmUՅ]]]]XUՅ]]]]\ֵOggS�z�����'���F]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]tNZ�mH_mMmk�mmUՅ]]]]XUՅ]]]]\ֵtNucG[m/m܀mmUՅ]]]]XUՅ]]]]\ֵtNP6NӶmK_mmqf[jVڵUՅ]]]]XUՅ]]]]\ֵtN�mf�_mm�/mm@mmUՅ]]]]XUՅ]]]]\ֵtNI�mw_mm�/mm`mmUՅ]]]]XUՅ]]]]\ֵtNR�m}�_mm@/mmԠmmUՅ]]]]XUՅ]]]]\ֵtN6?F_mm<mmݨmmUՅ]]]]XUՅ]]]]\ֵtN�mV_mm?/mJmmUՅ]]]]XUՅ]]]]\ֵtN.mmӄ_mmUՅ]]]]XUՅ]]]]\ֵtN �mR_om`mmUՅ]]]]XUՅ]]]]\ֵtNc�mk�_mmïmKmimUՅ]]]]XUՅ]]]]\ֵtN�mU_mm/mmo7UՅ]]]]XUՅ]]]]\ֵtN�mQ_mm/mm mmUՅ]]]]XUՅ]]]]\ֵtNz,_m@/mm@mmUՅ]]]]XUՅ]]]]\ֵtNU�mH_m[o/mm`mmUՅ]]]]XUՅ]]]]\ֵtNkF|�_mm/mmI}UՅ]]]]XUՅ]]]]\ֵtN%6m`_mm@/mm@mmUՅ]]]]XUՅ]]]]\ֵtNe6mk@_mmmRXoUՅ]]]]XUՅ]]]]\ֵtN,�ml_w[o&/@mmUՅ]]]]XUՅ]]]]\ֵtN-ԿmX�_mm/mmmUՅ]]]]XUՅ]]]]\ֵtNZ�mt?_m/mV@mmUՅ]]]]XUՅ]]]]\ֵtN(mh�_mm�/mmߨoڕmUՅ]]]]XUՅ]]]]\ֵtN 6M_mm�/mmܠmmUՅ]]]]XUՅ]]]]\ֵtN֚J�_mm/mm mmUՅ]]]]XUՅ]]]]\ֵtNk�mK_V糯m�mmUՅ]]]]XUՅ]]]]\ֵtNRa_mm/mmڗ]mUՅ]]]]XUՅ]]]]\ֵtN"mKj_`mmUՅ]]]]XUՅ]]]]\ֵtNBp_ůmm۫mmUՅ]]]]XUՅ]]]]\ֵtN[�mo_mm/mmmmUՅ]]]]XUՅ]]]]\ֵtNh�m@_mm@/mm`mmUՅ]]]]XUՅ]]]]\ֵ�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/empty.tta�������������������������������������������������������������������0000664�0000000�0000000�00000233262�12225024651�0016716�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������TTA1���D��z�)RLZ��RZ��Z��'��` _��������������� �������������������������������������@� ��������������������������������������������������������������@����������������� ��� ��������P���������������@����������@���(@�� � ������� ��������P@�� �����@���������������� ���� ��(����������(��� �P�� ��������P(���A��@!������ ���� ��� (�HB%�%B ��D���@��A����������PPP�`�(`�����P@I�P�P������������P(�@�������T�C��@�!PX @a� �����@A����&���� d(0�0 ��L ������������� ��@&" �E�(EaPtP`L���LT� ���E��P[������2`����0�������`������e����e��$@Y ��ˀ ���d���0lr1���I�&a2����`������*�� e������e��TI��LR6 �e�0��������&P �� �e�Q[����0 `�*��������&������`��eT�`e���0 ������` ����e�2�*��0 ������P6 ���0 ������e����e�@��� eP6������LB52���������P�L�� `R\!� ��&�@�`���`����(��� �&�P�2����jL`�ʘ�e�e� &�����Ap�0 ��P ������0�������Pe����L�� ��� �����$�e�0 �� 0WRI��(1a�(���I �dP6L� �C�� ��eS �����I������IL�0 Pm�2lj T����@6�L��A�  ��@5�� 0 ���@1���&(���I��&P0PF5&6$ ���(T������0��`�0�!L`� @Y5�������ʀ2�j��d0$����P)��ee!L2j�`V �@0P$0�L��L�e�3(l@�T���&e��L��ʀ2�`(cB����(eP �����L� L2 ���&@5 ���PV@5�՘���@P��( �2p'!M `������ �����I` ʨ��jE e �( � $����P�! a�`�P6\6'` ���*� �e@���eTC����@�T � ����P�@A�0����`k*aj�P6 C�2���� (����`!@ �0 CH`@(������ �&0Y���� ��2�P���L`)�����j@Ym #C1��($ �������(������ ��� �<���& (S`rɐ00 ��`�00 f �e���PF2j%L5&����P2��a�$@x!R2TP������`” ������'���0 �������&af�0�LA�PV6 C`�d���2�ef&$S!L�! L2l&I������T d& 0$�������0�����A�� a3 C���( aC �� (ʀ0����A�� abʨ`@�! �������� ��(��AJ������ �����*V-� ����� ��������x&a`Ն0@��0�����T �0�0 .� �����a( OQca��! A`L��`j ���� �@\m$�&a��A���(������0!yõ2@9aTl���\��0! Pa&a�L��������@6Sa��IՆ0e�I0$ a�eCLj#a0 � 6\m&eCjL2d�Ae����Pa(=̜ ����- y���( @5�0�� �a ���d�$ a A23��P�$Px�2&'I�� R6L2@! ��0WIx�P)0�P)0�՘dL�.d!L��0$3�Ax6u{�0��Pa����` Pa��������` CH$ Cr$Lep9 ddM��2 d0��pf�A L`j6'S[ɐ &$3����x8<$O5&gAI�PF5D0�2<'3  �����@6!L������eh 0d g&a0 C�A2C0��I1WIfH0&a�۬$2Hf��0eaA2C2HfB$3\MƩ@sj.r3a'dj�*aN<C���PL jC yS! @fN23(Y �mI"0 @$3d\$p2(0jF L��&0 rmd&��@$@ٓ!��� �f0 ��%0a$ aL&a83�&a83d3�� 0uIf!y<3'pm&C9 s5!L2 A��P69<a&gV d&��!Ppx8 �� ��(0S0IL�ʆ9g����LIL�9IF9I@"0��(0Ix8L&@f������A L$L����&7N A'0a83$ g& <O���`t>@pfRa298$$��\md& !0 3C<Pm$$$ 灘D���2HL�&arF rQ&&~֖̜@X��A2\M !g&���0 3�����&ŕ!e &C�&arf093PTd̄ ���0 3I�La&g&Lhd$393��d&g&PIQF&a+o)�Wb P Ù A2 j2uy��L 2L`|m d!L�d&g& ���0'$Hfr2ə �Pa @!A�0 3��2 3/<ʮf2d&咙s�䩏;9AJ4��F2$MKy `reG'�&ə��ᓧ!L232(f9G������`lO MNq!$'&��Ro9m9J���L.{5GT$Dd&'�������$393�����2yΙ !a�ZkkC!TPcAjfڮ�$393���I3��������D$Նd����0LXL'CjCxIjcΜ#!�fCޤ<M"cEC�����`LL ����(0\0\a�dx>v &Pae�sِ32O29 �3`393�� 3932C���(0 (sِ!L2C��`LL�L_z83 �1W{ ��0sfG� ����ˆs'A��������PA!��2��030sfC(0�&dR3?*V'3.0�`LL�0�`LL�������"!�F@PF�j 3a&g&eLL��00L0m0��@V M 3 $arf������d@ ?LL������03sٜmɑhE$ j$<����&��rf�e$<2sL"�2�����e3?G- �B��*Vl8<HxfrFF29�PFC� 393`<<L"��0jgC >[�T0_#P  O"@�&Ϝ?ơ���$#E@593` y'�&HxȄarf@8g�@ ZAC��ˆs~03`.{nYoMjbO1Ih`1HxHIyGʔSo �) *P[$Rf����0ayQA֖I����� 5C03'09y2sddp ��eEϜ3 3j@����`LL��ly8y+ 2,19����&kLq@��*sIms>A0wX՟)y&�9<�e31VE�BʂǾ��0fRTQE���|HF$p W6��!DTE`6syjD��L2GWA`p3g 3� 3k38���PFa,�2rxC�`91G@�*:L9�PV9aʨogY&y �`99@�� -'93���(#gϸVU��a''�(#0a愙9}Th ����@9<0 3���ԍ99 G�sp>!-a@mYTa1hc@f�M*"�`9H9zpH1V*"�0 V{sO*B��cA3g#3j 0s&��� 3��ϸH|8 �jTj�PFg8g&��f|au#HF|1��`朧�����@F�@2b 3gN0)?xUi10 �j��������Lxʮ8͢ 2B͙�L9̉����(#�fy&����@9<dv&y�F X5B�@3(bD@3'`̙��@9<L9�&|`@dppŪ!UG�Q,f<Kb 38"ky5;0 ����*c T��0a?qU#�@5u)2(ja='Cc$ Fx��fy*�șt;<P9<�P|C̜z �P9<��������v&DI3���`2·*.#Rgl;Ҁ` *,�d�Pԍ*(0C|mO>8����33@KX5B�B& -@�'̜3HfN��0a?:NَZ5 ���$#23���&68P6uC"F08<3ϙ9mcT8�������(#�3 sSC9aΜ�����&|15B����H|ꪣ1h`A:8U#77Ta@�,C}C��!���0gfU" ���fy*���X>YF�7=h��,H9<33kGc!����������9)sN�PU#Z/wi@��d+VBD GcPa@0V"3u�����@9<!���V9a�90ảap9Yi9$/w` 91�0F¤vvT!��PD̜��<�@F:Xe *زKPĪ *����F?gOZ=0R9fq]�b�BQ#9j޲ !b0mLErV2"Ӟ5�cPa@�BUqs �TPul€` %WI��f> �&Z9$����$#O VcPSvcaĪ)��aŪ�� 9c@3Ta@�� kTPFGle5HAԤɁ"T{$X 3, @c€�sx�����0X��PX!��Tg�*xS3��$0`3\X5B���:P���*X砊�� |  _�Tg���$|?V`;Ö:U#cmIP'Ϝ�8jy@�"\�<35|jLD 膧p:Aj����:j�����@OcU������|Xkݡ[vV �Lnha1Ta@��������1j � c,g>F,EDYT@��������@��UJM380S?Q��0bPe\!0*Y]u����z:kWX51t !I� |j"V��P9@@|j�����q,ޭ5z˂00b���8Y\8$����H,du1!2Ta@����RiF nIa.0 ԈFQN91joX)ӌ}*�����@8ͨªBTxge!e#Vh\X+}v1"���0.�����@���ƢbU:Jƈ߆~ْ,V!eXC%Ee왾# U81.=eF)[0bmg k}<֊*`vb@eBT1�F!rh=fע,H�BjCFa@c up:F L+1@����s!pp:F@1ƥǸjDc�������U.F����`q:Uq@08jfb@@#V�2I7U�����s9 �HVy@̧F�PI~V����Lx3.v*E@#VO9��P*FŚ~e*D���e3?��*v-!n3ŀB>�T_݁W|U)SU����dE@F`RMKc������*XuUA2ƨ �. hqa( :B����@c4PW}��0Zq@e:x4U¡8b1i���0����,p�bExY �����G]1q3wiBWLt1+-U:VQjBj���aq@�H8!uXx��@c|spr1jDS.<\ZA����@2QXc]z !��d#s�q.�񔍺!X5B�`CF��� ������u*~jE ��V�����R8" u#X1b1ZXcTXu#V0b)FĪ#��0ƫ>UG�������d.��T/ĊUhĪ#���@2Q���`1 �`QGisAxueP+����"vz�0b1 #FD:B!XuW}ejĢbغB4"ZCVbĪ#��cXWP+4Zq@Eօj�`6u<$��ª#c�����(ZǏx@��`q������1*jq fU 놮8bF}YUZpuQ8 h *Vz"b`ݿ^ǃDH(вA0Z11Պ��Ʒ ?LЪ1` ���1��PQGh٨/)F\uDcvWQ8[w>������@F)T#P->���HVX1ԊVQ1�w?E�P,���UG#C8PD#uSp@��0�18̙[!C-:úl}AěfRa8 ���P[X8V �,C[Q8 ��c Ke�EUG������q�$cq@@G#z Bj]UǨ9]j��XZq@��1 ���$bQu����@Z������ uiv jq1 @Oٳkǵ����������R85pu���c���QWjPxG\#pB(.A٬Q/:@����@(:ЈƤP+���cq-;_Hň=h Z eYX�@(V!���Fak;ή I���rX+��j1 ��������dG]PQnp@0��TUG4���ԭ~UG�� 0U#d !�ưVa8 ��R7 1B�Pţ�cUG(v׊�c9 � ,����8"����ԭO0Ckq@���W!� ���5j#�p�c��TT/��������?> @P֏ǶQI)aX+�p#c+~UG���PW!���Pţ������d����8����@2.U±�:<&Y,���@ l"H W!�1�����8����Rt^Z)U^g򺆩‚P:.]W�LkEP���� uG���� uO^:B��DUG kŁa2 Z6֗~DafUa`+N!k  *R0 ��cX+ uſǰI ��P \u�����$82g]-z6~{wĪGȲA�����@88 ��v=õƈ=/cmg*e/A+f&$$W!����Z�d<B ���PcE6~џ ���XEϰp�,h����8Tz xMl1Z�����4;��@Qq#29�6RƸen=HT#d֊�2EZq@�������@iF= ߺQW��nb@o Z��a8 ���8,Zq@aҳ8D�b8W$����Y X8i8в֭B �WcUX1p������ jc\2Ep8 ����@8F]u*:B���QqiZӬVP !�,:k!��G-L��8p8Z8d!v]r<`D������(Qu:B�����u#  ƈ^T�ٱȴp�an]rV!XA֊ !^xĊb \u�����Hሗ~K#qb0rX+�,ZcUGr��������:.qq@�HQ�ԭK?��QqS&��`֊`�����:C8f?_r"�`1&aR �� =&���JW!DĮƀP4ƈW �� fZ+4BZGq[D >A�í  :a8 ���Haq@p6T;a8 �ūZ Bq#8p���@E]<Ł���]z<$��a-z1���>^.J ��0!:B���dG]l 1�1x@eX+���><ZQN.v ����+EAe���c!*pu�������Qq�qFD#d֊Egz|�����������P. Xq@���:.���5QXqK?eưV`,^8uUG�_*:$Ue[I/6K$�p*Xqe@t_0�����0`)99@cXk ����PS֯gkAE\ ʀ�@(\u� ޺c2,�ZcD#֊��qiVkʼn ���L6;UC,Zq@���?`D^,H������jq88Mz\u*\uu?TRZq1G8pA����KCF]:B@Y ��� W֊a8 �@~PX,cX+�Bq#dY-㡫��!  P4U9d k0Kc#��� zv4'$a%nY %����������1 e!���N}���Q۳p8 ����@88 XDZ��Rqaή]C^H�Z1ezc$�){ ��,Zq*<jm@T�l+;] 1bhX/A��������@?ho@P€d z- +0]!��m6_rBBARk4 ��Z,Zq@�� u<-k!dbʪ^l������:q@��R4;+����|z��Lk�Ԩ :B�B0�� ���l ���Q- - �DNJ�RDZQ8𪃲:zj����HNJ)ƈWİV�2]��TW+:N1 hT ���^u��QqUG��������5c!��5«@ŁW8#�@(|z���Xq@���@E]|�� Y}݅z|UUh( h���`֊���F]|�겻B� a_X8D (z=rY"���:158#�@=;��b!P<5h7aPX* %�0�����:#�*/�������"x %`�*�Z,Z`֊Zƈaw c`:N5Y㠊 {`Y#*h6SfW=U � ���� uG!*F |zŁWfܸ.:he �������H����d<zAuU�õ� z^۳Zƺ�������G�Pu=BcV<@�z� ^۳x-z�Ƭ+| $�0�1,-ZGpx@���@Eu=B��cV|H^յ����W]9,Ӡ@K�KCsVh�������@dLC b%Z7+P@o{CxOt���\r&�@I+4�, 2R(Kf^l m[5' Zdi Jf0%Yl  6H��`L&ӲC^a ,6� i��MK@���%LPPvԶpM,6�1x[` ¶ RRSrk ����8G������Rk<�ŁW=Bt]������(QaVhN޶$�$hL^$���� 64K@������ 0-m ��@P/= $��0eI�0R+'+AѮFԘ0���� fв t]꺢gj�����BcDt�����PQ��������HqKʵ %M  ư,P0`��@PQz��1 u<OQp`8@��ٯ%�(-1\1+������:>(1�U ŁW=B���� (<ǵŁQtV=>BCFs&Aka� V@���0eRHXa E=W�aZ@� (  @ AErQi@���KNtDaZaZ� ���=ӿ.I�` [e Chia��������iIi¥LA0v2à0�HdV:B���p͎kK`xK ail��1P%='U�����@EU����d<>r2���r06,opƕؘ֖p=ņ 2&����� 2ò Qh%i�jg}g �p-i8UA8Z,ed!%$$������� _:WRþ3(P% ��8Z\.qZ@��������P'MKaZJ`iZ@���ƴ,iB++.d�`L˒Ro`�����ư,i` .7,[dH-L ����@09 �����@Ppѐ.e „K��XiNVf ,a����L1ZZ0ۮXW ��������*/cLж.6�( -&r$$� $���� ( MI-L ��@Pp)SJCPvG]q���K@$ ZBI@̘6<������ 0-npeP� .eRN'XYka����� 2%Mi �r �(eI�cZ! <P� #vl.6���m�����Dƴ ���D)M���� lP°iyii2`DqV E&֊��` 5����Jԋe"eI�Жa +oh2ٍm;L&�����ƴ,i���„Kw [!f ���Aa¥LA�����il `1\)xVFޭ4㤵0Y`p) � $����å $�nvL��TL���� 2*Vm逢ƈZMxX3I$���QW=B���@HK�,LpT ITs0�⤵0��Ŵ,i����@IK� }6|6|d4f ���\iJmAՆul���,eISh/K` $@Fl6�X Kxp{-1.p [vL��l`ih4�YbC(4f �ˆm7: $ U @���  i]mKzM z_ڐ�Hhr������ІPJ�@2iyii�����cX4A��cX4A�� l0b r �p(_VA[vIr��0ee1 ��ư,i���hNM�������Pb �� (CaY�������(Ulր%LJ+:B0@|hXD 4f � .6lia�����cؖ4A�\biT,;ކv57m7p" ��@{M`P{��( �����cؖ4AA9&����T/ 6e$��00�(a܊@h- m&۪9Z@���@aؖ0(m � (L`M$���0mI�a( [ ������ mK 2˵Z"`bl!Q]d2і; 8YZ@'K uܰ|=KXKzl8lia��@X1I$*m f^mGl[e ��� D��a[+[ bؖ4�@(/ i&����X ے&���������J*[8CP(W9j� wr\֦d��a E 6I!=H�������ʆK9!(Lv  n6! ���`1may9nw@0[ZLD�0ae �wU_(LR�\l"!.6�������� 2�������J(ndpr8d76bF⬁D 4&.6�������ʆ[90mI����Q-MH 0^�������(lC&ʁ���������%$��Z&�` ے&((LiHfP(؜l- �@ n6��0F{KtLpMH9Z@�H`6f ����1lK ��������B8NC�cZ0Q3(4�����c4A�ak0M$��„Wnh:/- ��������@ն>P�`1lK� vb ������ n�1,ჼD��,VR ukhp�[9LTa0`i)QM$@B3(4��Ű-i�X ے&��&\dwж0� 4%l"�����Ű-i -Lp*7,[a�8l- ���Jp+ ����� Es[APex]������PpXha`ia� '(�Y7' Km ��Ű-a��A:L4lY+ ���% &I .6���@(iZ4 wm)�H�Ts0��������������@T M� S{ne"8�,rR[9 l-Ll0&�P-/vDL @F\l"�bږ4��Ŵ-ѹA6������@T e [9���i[B ʁ�������@I!p&����bؖt���8,�@([wN-F0Le5\h`Zh[@������t _^Ʃ&K"XL"��&DbɾX-K@�����ö`H������iۆN � �% ����� q؆  l(g߶�`[4C i,i�0r ���������@Ib 0ʂԺpY@&H .6ٲAi+@@ .6����Bce; Lp Cm0$P,K@����� pM ����pM �@NK:�(%djQEs-i���@(ရb,CUs-i�������Br8$DBUlX~{Zx����@Cyi�eI#L�� N M"2��������p[2���@([9������8lá`XH �ŰmY 6 ö���B0IAscӥ���������,muϠQٲ���������LP(�aۆ99† |ML$8X4��Mp`ۛ2:% 2! % �@Fd"�@(�/2�b[H�����`1l0%"2l{`8X4����t-<A�Aۆ'y i,)lYҠ4X4�Mpsstit& �����bڮmK9e{ &D�eIdit& �������iۆ B @�������ӧrvvcö@q�@(H�ö���J8E �����(\Yl[�A �J8;\~a7wJD�P0esܮsTU2�����J86- "dt0\cpit&79Lp�'˒2& �="D˒�������()C���PR8E ��B {`=2ತA= Am)ZyR������%B nda�@qƆmK��bڶ4An2!M% ��%p+d"��Ŵmi=6H n2��� plY ���%"PhL$@U4(v Fу{Ke .,d��H,K0[4��5H+-rö`L$�������%Cbږ4Mp&x%s79ٰ]Nk7H�BjN[$����B @��,mˎ鶤AhrLZD��BIYl�2& ����`I�ޕئE>- eIDPŲ0��(NeHa/ Mr)d &D�@FDmIazyɎeIIn2MC{+)0+G|Lla 8/0����:&u����`i)6M$���XLmJa/L &x%+Ҷņ4ؖa���֒[#Jc P���������@(7ۗ'ى������tWXTm0؋L$���*Vm&)9Leܰc-!�����*m �IWH0�(NFA܏Mvq0ۙ!ܦC0!) E$"���������xaf n4@@q,��%" d͍]mI8 " ��Ul/e"vb&"���8Z8 " E2CF�������� ӢJNHF�$]4� &xqQd8X%/A@"!,qodI���`/2L�@qU9,���]/-f_`m�����bld/2�����xBIx���}$t0E&� K4b- ��@(7hya0(NzI0VH���@qrY����`1]1ݖa������Axކ#L,e [n6d[Np*0^d"!I`H,̮Zrk$[D�������,6Mb, `a6@����@ͽ ����fcn���( E&���� (Aod[������B7vx[B0Ds a%k68ФA"��.0( nixD��������� 6:2 `�������Z8mӄblJ:ȋLQ2 $2��Pl0Y5Ǝ$%jv6"!I^d"����@(ZY` C($/2X8ȋL$��e0���nξ VXT{)\ai ������ذmtJPA -L"�Eia$/22 7l[Za/d[Aa-1-��������@(餗v:U Z1/9Y8ȋL$��������� gܗ LI���%&`[������ i/ vXQa  ��Y8ɋL$��b-Cx, P�vކ�����p٦A؇(� IkYfWh��@V� d%T]g"; Ha����������"^`4dvvA$l$��������re æ)�����0M�X m:48ɋLFy�����,ձryDq- �@FrM$�E&{������`1\i��@(78}DqrKAҭ E �Y8ȋL$����������� ��jt& �,6Mbe\4�������jM ���Iov]LRWYD0��������D5N4��������(CD$r. ,A 2 b�d /0������� MOD�d /0��X caH"�����Io8Y %m^iӲd/b"��� y'2 ©\ 7H�����ݒl ��� a5H��t:6l}$h �d /2�����e&����blA������%v%p7:W]lJ8ؖvc"([8#�����Y8ȋ:m&)���tH�2 A^`"��%&�����������ZtT)p e��� tľ\`J"m77\.าPZd ���J: &�*$/0��� o ::D6݀3Ă #���-"uLnE`;~ @��m������pڦI,6:/U��������f)-}F����M򎛖] ����mnd���Iv�ti*/0����� t^a�% n0 ��,2 b���M� tW$-2HK����r$Odd�����*L%;&ݱr&%+)} IL×)D �����*w����@qRdSE���nKvLn0��P;~>@AѭMU\a��� e ��'*M x H$�Y0dd����`aTQ&������Io8.2Lb�2Lb�����������(NGFcr[2LPaS y/  ]0]\".7D-` �����bxLK{Jo6����Pҩcp[I ���,6Lb�d`/0!^ʳBPZdaoidaFeZ�������AI'"? nvIѢ*%@U0,&2��]6|}Y@����Xna{9| dQE9���������@VvA����@�@T0r h8!V2|/`"� { �@qpYI� d�����@(Tr& { �^`"��%7 #.0 �����%=`"�m& '{*.0 H]K2c/)hoؘdV$3f6IdRB��� `[b "s����S{[��`1ܶaS\a0þa(pe88Ld��2Lɾ2 p^nɤA*FCѠn$_(Efb��8T$bibFϵi [@qrYarYarYI ���, &8,1e& '{ ����� pd.p4W^)c_QR8Gb�������X m���Jz(_(^P(`"����+ E2��BIF)MD@N��� &2��* p7�����, hi 4zh{GU$BÙFXn !d_XE&AFE0,$e�����)Ӄ}#G6a �����T23�f :n������A Д2��bm : d�dt7��G"9 .6I$ ��������� (‹Md���vT| i-'H(Ⱥde&1����pۆILq>7C3�p^[$��������������� al LI @qrY Z80L$N� �^@������/}E ��G$LqLD`스(Cy1D 1:������/و"A,U4vMl!m@@B v022������a 21222��@P ibӊ;$zE%XKF@�ƙW(1����EeR`Q 4goi6 !������%</0�������v6,Q\AAF�2:Ҿ, KD��hb;H�hb;H���X6A4XtY&*6J $������B  $�Jx(_`"� & 6M"��dt7����� (| M�@(ipfs"dt77wK3a���d4 5 X₎jd@8XtY&BF{`U29nA`����+CE[R.i }QlA!%h@��d�a���� t-L`4(.h`\�ɢL$���8YtY&Ee"�Pam$6M"��� P����bmнVq}IMY0m%3f9<xS$P;-���ࡶœ���@%D$dI~ NaWHpmA`�U2BF���d4 de���, NEe"@FdD�Ja՛(�����������A[2 V]`e8VͩDL�ѨYMȈ�����06 i 0`"jEB������@ٻ(qAwQ I̊$I�hb$#�������� ��@&�������xx7�(6U2A H�&ԜeD@q6MNm&m&.Б]bH"���dt/0 ������C&�����������Pr[mY i_YD��������B a~M| ò|bo @y!/@I!��d2*.Ht$ڐuD���������J @�20m$�������, .cY&[e"����dP};H{Q$ P �(Nn]6e�P;%:ʊ��@qABg:` ���@,MF$ `.������"x(@qXuY&�����b0t$8yUCi�'mD���� P�� 3|," ��rwNJ_*IB�����:_Q$bEB�����'.D�������@{fp�(N6]������������PY4Xr&1��� ��S'@(ɾ .im&���4I2\/Ib@v$8tY&���@Ez*_@ ��X /4���@(} ����������Zةi$�%< (^i��˵[v or-</p QܶiP����p(_hn-) �����vH6m$Bʗ0CR8}A  ����������`1l�@ v8x(_@���������% N8z=M{GF@�d Q0P `D������� $����XL/pj���@2RxoI tbv ���'.D���������@]> 6Q$�� @����@Aإ Jqje"�Meb@/4PlA&q,q+��Pl,���`T| ��v<2�����d2�b3b(�� FŮ4opqİH(S� d3I!��@</#m<B7,D�������2�24���2;̚ ��� �(6UѨ`R\���p;8 ����UeJSl,���tcO_ N 2��T ݽ8<i*WPK&£;a7HHf"'[s!]UE[IIPܖP~a3 �нetL{[I�δ_Y P.4��������()<7( VUlUŎi/H����������,-]e"�@L( XU٠Yףr~ro$3`pQW%I����(N۬~hnHF"I�������� (}����]w/Ad"@"ݥiAG񚅈�@ �������� (AqC9VU ��P,��0 * |ShmKw�������������������������������������`@�������� ����������������@�����@���������������������� �����������������D�@�����������@��R����� ��� ������� ������(@���H � ��� ��P��P@�P@����P@� �P @��P @��P @@��@A@����@A@@����� � ������ �������(@���(��"��� @�P2@( �����"@����� �� P������@EP����<$�����``�(�������@ ���&� (�����I(�L��`.P&`P@� (@�L0�TL��$� `&�� �)&��((��L� L�����L���\���& �B$���$PHQ�I@(�BT�(@Q���I����D���2���$��0I���������������$e�P�L���I��������`������(�&��$Tc��&�$��$�����e��@��L��@Y��P$ )*!@ L0�ʀ2�ePm����I`������I��&T�2P&2�`0���I��2`�2����ee�C��(���2����������&P `B�����0I�@YCj��e����`B���A�������0 �0 @@Y��P&�0 ���$L\ �P�����L�����\a&A��2��(+��&)���������2��(&��@�@��`������$Pm����(c���(c� e@��e�����e�����L� ������������P� ���Q����e��P��2$����������������eL�j���P$ �0 0)j��e�LP�������P��P����PV���0�`�j�0(���@@�20������!����jS7 e����e�e�����@�����s5&00@��ˆ ��`�`C@5 &�2*Q 0l@��LB��&�(C���$���02���2�&�I�d������@P�LR���$e��Ap�( �e�$e�PP�eL���e�������L�`��I����� ����@m�0�0 L2���L���`2����&`�j���$@���(�Le\F2 A�0L @!�$�L`e .0 C��I�����$ a������IfHsjC��@5&@���������P��2�22��!Ce�������� ��&a3 C��tld��I0@�ˆ0� ���P$LS L�” <!�0��La�� ��&�����A!<02���PF0����e��e0@����@R[jL�� @�@e�e@������PF3 LIfr$ L`O�”A1 ��P�����������L&�0�P 沙Dl  @sd2!LPF�l�`I2C�(+� &�& ː& $@P�2��P �& L0ʠ����P�L`Ȑ!0x&a���������&a&j0 3@���I.@ epe&�0! ��������e�e���ee��@0�( @����&aȐB�`�&a0 C��(@L6� ��� Vʊ `�Ɠ̐2���2! 0 I������02�Pa&a���0 C�'g&a�� @m\mH2dH9:m��I:6 ���eTcLL2e<9$ ����eʘd&a(-a1AƄ TI0 C�� �Ax30!��&n2@P@F2Ԇ0���(0�C2��PaA��ʨ�(+3aC�<'L���ef������`$aIp� ����Pa(0O\ !$ I�0�ȀIxrx������ ��2�!C2! ���A����&a� aq51!ruI ����&aL'0�0!< !3''gd̤2�C�tpj! a��eCjf $e$Sa�$�� ������C�If������ef` a�1aP pe#=H2Lt&a'[0d0@��=-?\l <$@��d��LL C2&gjsxr����j#@0 ��� 'Ϝ@y0�� W{o$L0��L! Pa�'a �0! �A8 Ʉ2Hpm0epf��(Pm8<&@d�@f�0l83$L&a�����L L �C9 ̜ L „!<A53�(0��(d&���Tb p9 ���L&������@Y� �A2 px8L��������2H2��-��`&xrxB!LS a���L&2 3A2��(dd\mg<9HAmrMdo0&�� v0b C�� �`Bm�������@$C v 3 �0A�\6I�`CO<Lj#0aAB!�P[&�L`L2 &a@e2���23���fns0 � L 2��0!3�&aL�(0��& �������eCI3' A0 ̄2d&��L�3��Ifrf����� ���Ն���2CdgN3�&>-h�~83I0a3� ���2C����lIfNmpmZ4Yѓ;} ��� ���2ld& �L`rfe 沙 Qm8pF9Yo3Hǜ@f̜D�(0\Ɯk'5@H�����Ajeo<&����Pa&��@m Lj6�e _$S8sĄ0a0�� �@Ն\ouc& ���\6� R$M & ���L83$<93WdA ����ee!�lL2a&�0ɄI�@0������j<uc30[2s�Pa&��PL ̤l83ϟzC  0���L`8R!eE3`Ùp90�� ����d0a3sI � � 93&g&��frMadI0(3�`d&�L<EzHI����d&gd&g&���$393$39:e�C�(2HfSo$Zs'g&Pa&<GJ$ ���P!3O208 �AY ������2HfB$3- �fy�0a&gm� A �����A3<G�P!LL��0<S��0Af'yr�&p$C&<$DS6u3sI21`LΨA��s'̵6L2s13&3&$39� ��&03��`R6C� rmde���-z�Pa&L`rf��PT+K`323�mW |#��B0�(0& 3g&������� H`rfRa&ɇ���������frfef��Pa&���Lə09h$Cl>30�Ljxe L09l9g&�L$m���L5HjAx R3 !���|<Gx2HH  3930sF7&y 2 LL2�l>BxY�� .{8<*9(�Hf39Ph��� 3\7 <L a&' pGR[.#ᙃD��� ٧Y<s0LW� 393(#!�e9DE4bHx 393- σM"�0a&g <&$ 3j$<�rf��Ly9!LФO>I�������(#!���vL���0m��� <� <ժZ3?s&(#am'm A�2j 9r5&y`LL�Y[2,<9������P٪c\C�*C[z" ΐXɁ�0 I.)(;d��Hx&L��ʸZM6"frX[<g���LL�2eg��@y�(#g�ə 0\?��� r<��6rx&�m|`��PFkK0L�PVL�!|x>պ#(��`LL�03Cə ��������frf39303�0sݞ ��!���Lə ��P6̫}<0g 9h@��$#���& v<bDfI?9I��0sA0aL"�0\ۓ�I DM&<yK660 � ���HF PaXkE�����/{ҍI�fΙՀ2rxH9<2rxaP;<8VaHŐ2@&̜ə 3 3hEh�� 3&v08Lɡ-׆,w0x2H4�����PF����(#Lə @9<�&<Cۜ;x0 �����`朧�&<<|V48< 3 3k38`Va=#�ad83��Lx8X!�$#?3gI��`Ǣ<D`.6c` *E �����C 6!ik=U��ƠY-;Ġ€@2b!L&-|pU11v)b@U$`&1s&�(#PF?ayΧ.BDM"DHז<8�~p@��HF 1Aoc! d\Q:�j!$6 $#dD��fy&����PF(#9OE9<�����0ϳc,q@�Bs���*y/����`1c��@qU#�1X�kzjYlB���YA֖z<��@œ'!3����&3s3�������2𳎑fRa@ɈÃ`23gNÏ9��a9O�dd,;gR`1hp!�eeϵ�BQ(933<z"����ʸn59 &!30sL���(#'A93H=Gΰq@Ơ! 47"��HFa"B;59�IPa9dD0fA3gp28uÏF8j��@:ƪ2'd 3'��0m>�*L>GlTa@�����d9穠lɧֈŠD"3�(#_dD�f}Id<Μ����0sγ���PF|5B��`\ӬT6 -UDZ,BC����T#":@ �am$͉�!0aE|g%̉����� 3'393&1�fyXR&������*y'A#ԨAq@�@2rxO<$�0F .l٨_ !*eRa@���$#|���*RWx����T!̙�%QnMBH^��`g"ed;z0 �����P sΣ >bƣQ̜���0sΑr� F5 zX�y?8 4)bD Vb����$#s+u 10 Jpu<bUʤ€���!ÃP̣p@�̈B�ɈQ?�ٺ#V��!Pw\������(#����PVP~~"FȚ`& I�!����&̜C�z`,VcB5C���`4 ��QUt%U#��ԨF���:b }* @m)g=%:WijThEZ#!���j5B0yj�X��̙sX#$Ȝ#!0snxJ�̜9��0y?8�EDrxxfQ *�F��`̜T� Z# !�� IT*;-@(#$3|Pu"��PFϜ9s!S#(3'am8Pw .fqC�cPa@:ACFBdI2s"�|F2���0s2G:{]c�ˆ ����TCf�?W<V ��@2`�$c �TxuSPP?YAj@ ��cHwV%D@�,�Ro秳G- �����U1q� #0 �����Tn|fQC#**L(~TCk #N L4��P9<0x#V 2Iz߲aa��aAl����1`X 5���ֿ? e�` U`bzV # X:pkU!��` U!c+ V5C���@kP #����@" XPa3ҷ#�;aJ :5*1Ta[6=ò~ R*,C-5CڐA֖ ]!��bĪ1� Uf p�(Fs���q?��������ԨUXC!X5BA4P�S#'lV땞u!�- F,ň�����Pc *x[�੣F@8y<8 �� u+>u:T4b�1c[vCq]1jЈU#ˆU#�����(b]�����Pc\):["`@E@jF�����UX@2�� u1b8Dz�����*XuU:j���������Tpqpc�dPCd b)FЮB2ղ3ˆU#�0agX ˆUj!lG\5B����.�������)"{<HiF 0hW!���H8 c5j �*jj4p@�������jVQ��P Qq`����Pc!�@2Qj �`#,kN80@]a @cVDDCaЮ ��f:Ɓ�Quu(hbxD1E�����q#Vpb�P ��Q+V!����@A-qpA������j:8XZq@@T!h;C) \q@��XZ8 �T:SB��HC#b��10c \AW}lgc-������������1.�RWXh`U p@�,!Tƫcm3C`D]c@Y�0zq` jLQ1b�XZq@��Hg**�����:Ʊ>5��1b������3Oc #V!���d � u�Q+vvKqT%m]J �� ���*n-:ے(X��Bj Y#~]2E���01t C����$c: �1�uDž1 ���� 㨋6>4N3^C¡e Sj%0 � \z@�������P RFڍi6֊#F,ňXf9lN4b��R?4bHU� ƀ`j���P���Pc!�(:` .t@@T 4 k�*TkDDZq@�����HwUPl7o����C54Zqb�Wcc\6H������@z뱮#������d^{�G]eGe��5tx`Ɔ(�������㈇4h Mj�������cu5ja,CxfX+z PjňUG4zBqh Zq@�B�B0Wu!����$cq�*Vz` ���PS~`tG Z1e9ԊP ,Vqh����Rxʎv8,F:H�XZqC:B����� u.ԈW!������� LuY 1 �@TV���jx����zmZq�aB� c>KA0zmB\vʮ "V4@����0;tphᨷJ!0hU �cW! dgۻG, P+�����U:B���z#�Eg+*FV(k;kjѳxغ!RV&H"�����TˆƈjG]�nQW1�1kP+�u=��czgV��4S8 ���*Xxcu W:1v1.!<l ;E'Yai � V �Jahw;ꊇ4p�����*j#Zq�P(֙~ +vEAl�F6X-Ā���Z<� Ap8�ŰB� 4(G��� ucXIHSq3)D hY_k��Zce cuY6`A�!ưV<PDZ3XEȀ1B^Ȁft 8 ֢c���!:q���XƱ#��Xce c@8H]]֊�NqcGٸ~G0�������x#8-Ha�����@Ia;#�eV֊زQs?���X *9a۟=^nFe)Ŭ: �������P:YB b`]Ua8 �u=afvQl�زT]BG$���ưJCW~E ������"cHx Z 㸾qmcv}1D�ڞm8jHHqm@��$�ai�� Z _mTeX+���� l}i<BW!���1#q1���Hgk�eXQW<W!�Q#JJZ+��Dk=2v-U�� k���gV����*⺮xbBTZ1JZGa8 㸾C`bW_6% �Em)OX8 �����-Zq�W[������$4ӯmD��ڥL���ra8 ����:; Z,3=A`%!��,ZqUq:B��������;+�����㨋�RqEUDZ";qE�2vPvW!F,:ׯ,2J,���� jDTIcQqcUG�,Zq@��:n~(4GK\����R4;GJNJ!�0U+\uDŁ(:hT̪hPQ F( VPk3\������5q=mwE@n,Qqઃ�������QWЧ׆!A���Aqઃ֊����vH)],J!�Ł1��@t6V<Ƶ#T8/:@�����Xq@ mcK� p�:BŁ1ۭaD �������� Z+(Pa a,������6* ����HqE�$8%(\u����iv+ҁeX+�B` ١W!�����H�P.W}e QqUG�����������㨋�HZfkWC�����(:.��P.>gtwb@0W `Ċ:B�������8"�������jU?#PJ 8h+:B������H> QqUG@(1٨ ����Ԩ:Bau [p l��� *2Gx=V ��� uvX8 ��Q%�q<͎G%'A)@�*A���X���8����x]_G;&d2E lJ"���P€ $�*a8bŁW=B��!���������d1ٮjUh k��1 cXٱ^PB5B���ŁW=B@^�`,^>N1 KJX"��C[vʂƠq~ɉ �&r�����@T8QDZYC �������Q/u,, ���j -pUtI',����[n0I���% �ZcV ����uB��5,ú2+�2+��!�P.|sC5Tc8n���:6H����X Unh �ҁZ TW$mH����KNd���`1,a��ò � t UcZD@h���q��C[Ae4S�  $���bhK �����p(S2+`���������Qb1,K8ZW<䑖 :fMR6[2Qĵ MQoŕ@�����0UKjc[&���� n.,Kx@��Zk=ȅW-+EH�%C2i $������Aǰ]Tn@0( [H��cXp]6 ���` m%=V�Cka�������Y e0LA������a(XUCNk\le �Łz�1-���{Էch�P8* �Aq$��p[m ix���� E֊ x)T k1e-"�8qR>KMBDh)i ˅`CZ.4) J��h!H���R�` m ֊PLw$ ڄ"le �-a -|[hIX D^hA)0%Y,Q4|�,6��( BR e2,6 i0(A[hPB��@(aVPeX=cB@ 6H����X X1WhΖev:&H������, ��(Q^5u}LI^v���jih!�@TxiW=BzPx#��BqU�>z����ƈoݣ^񠢇,z켓uF8Ί)@֦A �^6Űqj]qð.z����MӲȉ*0���� 0�XLMpY������J ��$qGl4RA/;H�X\C{������� (iX)��ch[z HC 2�( ae���0e d,lm6IL $�kT0��������i*J 6����$r0�cZ0lBW9x��׿ ����� ]v)��06MKH&K�pH 6 @BB H�����UXC�,Yk4�€L ^�"�H,6$Xl �����Dƴ 2�^A}VVլ$ rv8tZ*/@�HP^$���0eIT 2$MRi����� ( )������%+>v0@ư,.6�1�A!].�[ *S��$q9,K X����TpQ�p!�t0RF-- � .e ���\*S` ו�WaY9(4n]`���HphW*/´@1,K@`  ����Aј]cX0A@PpiTJJ� ���*j(c}|*O`Z@ `@aX0$l ��ò ò "�ư,i` ˒&�� ( )��� 2Z6=L¤4U[y %Ե ǥ&T���T]8} %l ��XiJ 0q R'Xa0�p &��@B\l ���h./aR \l QUl� TaT���������%v,lK@0eI*6.�A6����; Bm�0l0�����dsr9 .FoS{q� B 6Hl6������� ��pJS������@d [�cXZ8 \l  ( vFsr#h41[[Ҥ40(MIkaB "!�� �����/c[ ���������\[pJ*a.WXL ������@ KK [RL9 V m"%)/x0i- �8A6bd}З $ s �������PQ?Ɖu�����Y<遊妵- 0-K@���+=^4P)H�e Ӳ  T= e�@aZ0 tt@���LZ{yRk&@h����� (L)0eI���Ș4Aư,i�cڭrVRiC�t]���QW=B�H;li2H��1+K@����҆AҰ���bX4A�����2-}*e ����������jLS[,i���d��PR8) jS�ò �4tBLu9L&�J[ � K ��0R` ��cX4A���% 2��������"K`]zٻp-i��++8^#xM$@.6���0! hHyCY����� fh]4A_2/Ia^2"e �������x�c|L)�������(^(SYP@BFlBIk�������Ԩ���RC_e �bxKy:.6���(N�������PF}[@��h���^ZXZ0�,eIB .6 ˒2l6��,a���B .e �KOt���JZC X }Lm��heul @f&h͆P(. 'Us0���@koa鶡�����1,K@0R$�0a[m6�� (L %MPPpѐD�Ķ7; &���1,Kò ��@b > D�iѶ ƎU Nat+Od3ZcsUaKaZ@@aZ )bH�@1Z蘶0��)kR)@qe ������7K fKcsڲ'D��������Y4-ј,i�Zm/`ka2H`&Г�27- ���1[[An6�[5G[ ������ʆK9���JVۮ��˫]$%p-/vL�������@P‹>F-- ��1lK ��Ll{+ :oiebH��±#N�@7yM$��0lK@��شB?M$��$0͞hSʣj_,1��T r.e"�����bcvL��aM斿52%��@B,,"P�I!Mf ���I5%<nd;mh[@Hh $�� p���p;.- �����8Ʀp���0mI9lK ��„[9&\hҾ}I�HhM$�$4&���c QVXh��� 24����0cMӃl"������34`/@7H����AT.SZhD��0mIAaMf cܴmi���������2L� ( hh 0\^������ ZyĕmiD��iyS}[Eˁͱ*6@HhʃRR&���Rp)L%Ll"�P,K6:Mhe2"��8d� .6( F &˒�H������ 0VA���@b = oi2� .2���a[a&���„Wlh]]6ٲ OJH��a�cےaFOP˒2̖% ����„[9�������1ڇm /6���( ےf �ľ}U!êM"AU�D����������rIƦoA\lK@˒" ��0C(4E&�����@da� 7������D0LPP^&�v-}H�� (p�H�Hn2��AရL$�����fa�m$�AရA�Qo3r˖�P$/rȰۦ$9ؖ!QxH!M&r,K4'ے As걹������Aa­&D��ö ��@P>ЋL$��@P8r9 In2( vKνׂPr,K&Ki& ����%Lxс�,mJA d[ ��``ۗhbn2�(N%mI���m@����������T豂%JBS�����5u4a�S{HxK˒����{`J"�,f{[A X ض������@ICx" �7q,)êe1I�/rd &D���@(z A~QOmgX,KD�����Űm$P/2�����$/Cf�@F$#PTKD�b48M$�@F#rp˒����������Qa �öM&DŰm�a��J8C& �������(\.p������r>ȋLHeI\'yhRm䲤�eI�����m ����@IKxBF#D@q,i������B ����DKyLbض4���UE����m �ö  pЋC{CD������������rI�^t ��ư\"wiŋDlͬ����rE&�2/CVX4`Y@&ɈeI���������"p&�`1l0A����ja+�PA/:!pЋL$UKAh N6- PhL0��PlKD ߮.K&���&D���@N ���Xl_$W`⠪Z\]a⠪V-&)�������p(:E&�x�_ ]Tym!�`Yd= 2M&���2& dF2As7\M"d�U//ТU/id[J0Л$F��AA�hRDZ &xM˖���p˒Pvs"I"���xс��&ꕷ4������p؆ -" .v~IOh8���2:M&����-;ے2a/d9,i����#v!�r56]]mIi0Mvgے2a/ Iے2̶% 8X.H 8% "��mI�������rыA���@I7���J8M �@(79 P@����z*KR� r:؋L$����+V�����J8bo��� pқ$��n���B 'Ɂ����ji,2|Jom(nNbO& (\nd !D pJ[Vcö �ё" ��@(iE,qpkOk&KJa/dcrY1K;% L$�����%&�������PB �������I_$ey.iYmwa ��P1[ \A2 "�����������j$ �iF\i p&xyQ �������������T.|!`ɶ 0a7 MˁK A����&�e(e{L�@q-ـ](2�����`anrIzY` A$+q54 L4H���PIo0Aar���pنA�`"������jit:6w۞/@B"(tH�����,˜xL������X.4IX-O�;H�]E"�����p6F\Y \AhH&yDq-Cٶ fےe��������`1<ZDdt/|ɝx!&ĐH,D d2rEѭK{D ���� ��������D5N4I����6,Z0p٦r,p3X'5e0J�ݱ.a#@WI|!3 R$[U `"dt7 U4hpՍI kT(T]g$� f[ ^ 0 L$@F' ϴ : wd3 �Q&+]E"�8ؖa�.0mnv&�ɶ.0ٖa�����bl$J8 6 7;L_\@FSuI����������M/t4@pH������@(7u.0l"94v �&��P1[ -l[A��������D5N4bM�lR4 "�.! /0���Ფd/0������PIo8 o-6J$�@Fy�I^`"���X e ^`" Y]ކbPZd ���X mD���@(᡽L;mv1II֮D+=% "��J8;nZ^ l[A�������MJ8 &PI^(c7v)���������B 'M��,6M%a_6: L$������%m6%�% }/0��� ʕX=L[ d/p8aan4bM�����@FyǶ_d������̶4'Q(m%:;�������`aXtQ$8t]@F8ն,’n0[.'ux` 17  LD o����0\a�X m N{aI"!����Wa'7I;Eـơ(17th&@0&�������XLmD�Ax8do����0]apl0���`1ݭMA��XLp SD�8va{9|0_@B����@qZT ��������hr[4StUieF��@qUQ$�������Z8m$eh o0kbCh o0X8LQ D�0�%[_`"���������@TM� �Tnp7 d �����0\i�����( ��B '},Wbѷ5_= B�'2 "������PC)-<DnzJ7H��, PA(I`"! y):I| eXl%�%`-- "�d o8bO⤫AA`"���Uͻs%&eqrYA {`0, ��beK߶���A`"e��������%÷ ��PI`"��������Q-<l$!tH�PI_`k +,mi.w%=�к5-$MTE B�b o0).3dA`P_T 1 I�P,,٢"����T}l`dVR˸=a B����@���J: L$Te30 8N@LDwL��������tpBf2D�����,$'*KaZ8L$���@Nc;So 1 ����AF@ ddQeYA&almi�� y ��,2 skpd em7~$9+(&n%!����'S*vxY>��r4U-i���%ze`o' 8YTY$B ���������JJ�m; "�m�md/6H�%[3 7ȂXafSr\i���n4����`1ݶ ����o/Cj0}E������D�������� e.E bmA��m; "�XNcso˧H�������������B-<)D����`cm ����JzX^NE&poBI2H,8%i}sae`bJo4������pjvmJ/2��Y% 8, ����m; 6cP$vl&V !MTE(Nt۾@ ��Y8L$����k 7cտV%$PݾYL�����Y0eEE"����E:s%"�����������Qa�StOlI(N.-&���P҃D2 "����B7vzs@�Y8e$����T҃QF`t.(#Qa �(.4L��r ��&�n- &2:ٛ:/4��(jA,i� jm([D������ 0I�����PFkui"ɢ���� K�M ���PC��@(| �tۦA��� t]`J"����������ڿ-2� Ndw(3U¢e��p7@@qN ����$–h���� P�������@&���j<^. ������Q0I%=/6Jv"��]qܒa 5I�����̲KyѪ8](U�@ 2��P,,������$�����ONbV~PFŦ(j ;TKЋb0@j�$$������rmA������^x:7]^N H���N 2 brY2 "�@/P�Tvh),MH lLvUdQѠLpP]D"��P1- .&ϩbLW$����d;H�������,L/ r[V-Ku3Ր,r��������U7D����`qM\yYFe9:7u#(w.;hT�TP"�do`"�����C ���,wk֞}LL(4o������A&4nnj&���@ɦ U&* Tޤs5%!������P e\'&r~3Nf" ��������]J;|(_`"���X_H�@ɭm��+K a5v{h@br[A��@䶌זi���������@ ~(Ŧ6 "���*"C2x~uo- br[A��TLn4����Mm1O*s!�Qn`0nI�����@І*C0- UmE$��TҩZ:7B �����1����� ^2:&/4�����^pjo0p*o0���rd2�Cx ���Yii��*T`t/lNDdo $���������ZzjoLd������ ԾDPCy ap[fW{JfC��SزAivvVR[ I*.C"; 2 bTҡt{ hAcD �������eB-d$QrI6p`S$m0��rP`b����������vT`9l �vIa ��×L@��TCyg���bL�, ������� sG7w(���* ;���Av0����If22"860H�B:طY���@Ex(o0mbp[AJxn"1μtݕD ��T ^mi�*᡼0- ����X-݈FWWXNnK �@KDTCy�������BKO Ld�@-=7�����E[:���Tl1yH T n4����lb'D ���@"1Ld�����^0um)0$//0�&j�����boB< NP������*` ���XN/4‹Ld���������2&2��b\u�t*o0ܖi�*oAb �������������bho T�2 b�����e;Lb�����eHO M%T\0- bD"#"x(@F��@{6HTRvE(0PXn$!Fukae 1��@EP 5A@"sͿ�������P<o! 6U92eݖi2:-D'P-Mb�������{iM$HyҲB �� &2��оM 0��m9:7�@qp[I ����˅o'"0UL3����;7,L @r Meb����*xEHR,6 1��������4,"_.Cy�tpX= 9+ e1{YI,-<7������%=_'<{R Zxho`" MeJ�����C{*^iP,$��Te0Sb6$! $�,xho4 SaB+ D���S{e&1�B Fe/47dj""����� (S{Ú/4�ĂQ"�������������P` ����ծEl�����iyC`We������X޺A&e���m&[ʇI8XUYY�@Ly$b���8XUY�VM2U;ʅٞK\0���@en' %hi+X-ip_P������������0Ɲ]F@�ȂQ0[8ٮHЩt 0p/Q` ��*E4l`Q$5k! ���@e&1P1xYI ���`9|UFe!5&mFnO ��������r6Mb���,i"������, oU0���XvU���X(������� lwܦ������������������������������������������������������ ������������������������������������������� �� �������������������������H�����@��������P�@�P�@��@���������(@���������� ��������( ����( � ����������� �����@����(����@ ��������������@����@!��@@!@@AA����@��!������� R���(�PH�@�D���@��������� �������H�@@(���@E� @��$�� ��$`(�&&)` ��`���0�s P@a��&���� (��LB`(��$�(�������@������(�I������$@ ������I���d�((��$��$@�@A)(��@A���U��(����L��P�� ����`$� &��0��E�������� ( � a. ��@Q������ �� �eL��(c��( ��L��� � `!� ��`(�� �� � &I��\6 0`H�`$��@�L�����@��P���e�������0 L2��\�����f�����2���`&�� ��l@jT���������0�����������������(c2� �`��e�C��� ����1 �e�T��l.0�0 �2`������ʨV� �$�����e�C�$�L$C`r�P�$C���P $��s5N 2���$��ee@IA�� L�P�e�L ����2��S &������e�C��ʆ0�e�0����A5�&�I!���0!� �����C����ՠ��`@P0 O�C���� 0L��� �P @�T�`�0&I�������!��P ��I(������!L�Հ���@�Ԗj��f$�����(�(j� ����LA���0��$���T.d��@5���`�&(C ������`1 ��e I ����0 ������Tc��!��LB��Y0�����PT& @5���`@%L ����&��� T!@�2��( 21 C�`B�����e����@�����@Y�@`@@��������&�A ��(clSap��(���`P6L�`�������e�e��P6ɔ$ e�P[P$ a`���e@2������ �C�&��`��� $$� PI�2��������&�0� Wd&L��PPV �՘�P@YI`��(``��0@՘Y L.�@�0 �Ԩ�0'`�&)Ce��&a�xL�C�j���������Tc @���2��2���Ȑ2@�3I$ a@�e@Y5������eՆ�����&a�0I(������Q 2�d&$ a�&aH�����H0P\!$L�'aOZ� ����IeC��`:Lm!L�@��&aH�Ld�� �(��L2�2��!������B��Pj @WR �(`T՘d�����L�`((T ��0�e�e������� ��������� @&�aL �`p̩m�s5e&��0�����LI�0 CI���@m ɓF `�YTC  a�����0$�����L`TI�Lf0�����L ����6C2$�����0&a��������0ɐ a�21� 0 @ʀ�`0�P&KIP6�&A`��P��������P)3�Q!L@���P��e0�0e!Tc�������2��II����0 C�If��0V L2L2 e00 j �@ ��0 3P 0�L0���@!L\m&, ���0���2�(0������0W0ɐ @ddP6jL�2�C\�� <� 0 dAL&�Lp�����������2�P6 CU A�ʨa'ala0bf2j@f`0�Pa� R �����A��A&a������0'a��@��(0$ ` f��d���0\3Ղ! �0! e$e�� a���2JH�d�LRF���� �# $C.{Nf8A0 Cf������IP dQ T<  e0��0l8$ A ef���`0���0 C�d(M5� KjLʆ0�0 Cj !���`rِ uj3��@2kb$ L“3O�����P6��0 C���� Ս� A2��& gr����2HZ 23����@��A2I y(.0 L a C& A LII($ ��@C1@��\ə'@s2O$2HF ea L���(̈́ˆ!L2df���� &0 ������# 6fee�0!L ��0���pjd,�L``0E$3��&a6d!g(d&0&0l42Hf����L��`3� �j2IlHfBڞ$B* ��I.{0 !9L�j3Ld�A2 5Hf$f8L�2Hfpf�LpA2��&a8$ g&L<j<9 弶sF'� @m!nL0&����L`8eIlsC2b02L��IL�2ȵMj`BI L0��j#eL$Y-/�pəa@̓0g Ù $ gb<s0sVb09<rdb\b�ɇ��@mÓ0sf�A8LT9̨A2�(jL!y�����3y>Mb ���`n3 �@YY W=(��(\$ 0#$32 3_O?X4R e4 *"�����&09V$0C`@ A2I932pfa0WӜ3P|I�Pdre'����e@fș 0g0 lCle?GBE �P1r!@&L�(:y ���P#ၜ���0ə 2��b2&e3'arfL&C6Hf�L`H|3)Cf.O"�@$3��(\$ ��� a8yma̜gL(d&0і(Hms&&GՐeL���� 3je 0��h��@HXF>�9��\L����-LL(dF < � $<$0�����2Hm0���� L2Hf2əPo L�(d&LفkSK6'D0��0�&frfPL�2\''3՘���@\�!<�Ty0(b&'gp <Ԁdmf 5ȵM�����f}jé a&LI����� r��L23jf����gIB�L23�@Yy&�!3O���efB՞`c.1�T0$2+Km8yLb ������!<L y(H$����60����(02ə!ə ���ep̤ C�&<$@PLL���� �03*921Lp0 393����������@�AxJ����@1��0mPsID������������L9'0 "LL�����*9&032چ3s0���032Ho3 93�03��Ifۣ<�dB��ee]H( D�� ��(C�����'|͠ebp귌r}dL��0M-!�Lə LN"�0a&g&��������@YY��&hˇRF%93�`LL`�@kg~򟪀�0QD��-X'b� e����P28ć&&���� uE���`T\y֨��C��03� rf���L3!�Lə epxepx�epx�� g&�Lsf<Q;C�2*B���ȩ[(,XŁQC8Њ���j!�� FU<� NC�\|5*NYh d1px�!Ƀ�ᇡ#PE09��P�����frf.C ��������&<|Аڒ3<x3IC*Yj ܯ ���ʸ~ ��|U�PF 39#Mn%s rCźЊUD��� .-=Xu2"4�Px6"��(#_WTE@9X������dfrf�����(#vdeGDM"�LI0���&\g`&'`LL�`u{h2rX��`¬vfa&g2rxees$ e\c!F*t � EX#VBL"�� 2rx&eL�f΄9HL"�ᙃG8CtĥA6UcD!b&�a9yp�U@G#1Xƈ �0sȩ7 3���e<MDTX"���@2b� 3'<L>k1��j L�0s0<&̜90ả��&̜D�&̜"fN��ۃ# ?k=bcPae51P5BrsdD0 IA���1F:RW!���Lj8 2X+���@0 �PF\s@E&̜9�eOīC�����(8V�$F rU#4C %1X��(#9p0`F������2rxL9����(s[<" 9<5PsaΜ@9s"�0 c����*(Gd5F]Z#d * XGZcj"$3'���`.j@3'f| jO<5B|dD����2ag�fy~C,rZ\Z(�!b]���! #FFTQg T����fy*�����p*"930dmb@�̜!f3B�PFO5rx%93���&̜30s>+|<#H<ՠ�0yN��If 2rx$3sAޠ fWۻ��B,6 С5B1 JҲb:j�� uMd1'f 0 �9D ��`LBfes>q}PZ# !T8�@9<\FBPF�0a朧��$Sy> 9‘vҀ \�@Ö�2IŨ Y5B dўp �ˆA�O<p BUNd AG=F������PAtj d`1Ygu!¡Ck���Q!B�š ���T1Z6!�Q5BD!̉������2�� 3<������Pc<J̙LNnym@0vxLc8<ھvP�T9 ��� '?q �������� >g1gn@i@�����Tht0vUPAam3 #?g` * �8PJ1V1s# �����`9OڒC����.#_eɈB��Tft:{H` * d`@M]XF�ACq1*��R1*)U#����| d���j#FڸnW83j#��9 `ԛ^]ԊJ�1+{ĭX��.k ��@B����@cF20 ���������#,�@��59穀9|u eÃ�9$L-?*@ˠ��0sN!��s�������r v&yC�gU#d `<s"��0ᙏ"aD~u ���T6 `#G8$3'�����@m�d@m|�����f>cձuQ !2If1hp ���� 3T��@I~>c�@!/vUqY�� * �����@Uc0@�U#��@n:* - H1XjA ͟+U#� *,�QU!�0g1!���TP?,^��!D١W}B(aĪ1 )Uk;*�0bU? ����` XT�8j��!X5B1b)"̉��˟��@2bp)K�@M݊F!�Ѳ^3;dgѰX5>Ve"f<5Ơp1.$E1Ҳ3€�FݵPEYaP)B����� y׸jR&-;xU#������$Kq1Ts! ԘpWЈ[7pa@���R8 ab- �����*Xu��ԭ:TB@o64e8$�����Wja@��c�Ht!Q6k<Z$l $')B� :Ƹ1!�1€��j~*#�!qc\lԅ>5��iɲcq5B���� "u<$�0*Fa_a�ˆU#`lRz˂�@v ui iĭb@!X5B��0b��*xfV����Hx.]q1��1.s+�TQkǐ�0b!X5B��,!,ˢ}) ��:*C���PA뎣#!����dczF���\X1JG�!ĊU#oguрP �����qE�PQU93����ΨzUZ8j� zjgZtTQ pMP#V�B͡Z#�@#V!^x# �0Z1ܵxˎX$��P+aĪ2*9JgP#V����@B��&[#$u<D�ˆUL���fc`� V=ZJg+>!��cGll>VLL���PUG�� ���HFuկW!��VP#V!�!+~Uf/CD1ԊF:B���������@Oz|=XYd B�V:FaĪ#����$cuA@:B�����$c\DKg#  j,|UG�ˆUhĪ#0bF:B����1 �`QG@+nݤK�k=Ŭ!Zی" eXDT6aEgX+!۳ �����!8�j�1u��aĺ=RؚKua2[P+s14FĪ#���*X�cc Vj� T0ba8 ��d#��������PQKgG ^4B����PAkab#4f8a,V���Zw|` YG!d+�����*Xu/hW}k$�!XkT+&jb@�`bx:FaZG���!tW}dc����cq@aZG���"@Y^!�0b#C8 �Ƭjq!ec]Zq@��������H8"dVU0q`8p@�PV#b#�����@Ez::B�����$#:ȡ #uA՞a-{p@�,C-{p@����q��j|zvA*R^0c���Zu#���Hac< V��;{E3a���18 18 �5bĺ=]8u$�����������P��$#:-[ d mp@���0F<#uFi_4EP+X4S8 �������H8"�H8"���H]Ǡ�, !c!c:T ۳Xl1( Y4`Z�C8 _=;$���bZG���q+��eU[}W;) @e'@ AXU����@2Q/iZG@(Fu�DF}TPv4jC,CV ��aĵP@DZCdUigNd$D�PVYJbDz�( jŠ݊C��au{k5k���PQ+u��@Eq����q:B&N�����H8”]HgV��� z` =[ b*=]8YPSvb 4bbZ+4-*h k1����� .��*x��z��!\B��� uS1*B�0'xZ���gZF����*غ c@���Tpc=B��cxE,��k=B����$8ꂌ11+ o!m K9H@an(#X#z�Ъ-{Ԣ SvG�PuH5etw@ʮ3q3zC@`����!#����� z������_xQ zL`+n(��2-펺@cX+��������@2^ �HqX�pŵ>#1=Ut���������@��\8^k2Q(Akc\rV���!qG0egkD�Z-����i '\-sA KahESV0 C!��#oG]���0k=B�����dGXz|,DKHa0h2U����k ���� 2!< kr KH�����"c pV)lw!qG!qG֊ ׊Z ע������HYըǡk=Bm}i! A+9Ly͵}l)H$����0������$8E���P`\!�8xê٨?ZjFh`Y<l � m3ى*J a)G1n( ZF񺤩V � S^1C[qbZе>@)\ P [OBS�H(Q+Ҡ:@�Z�֊xhі( $�chٺ4����@8V<qc]�)\uHe*9Lye@��������VQ8CZ9H�����@W\gqx@0UI*=+@G\A�J5eZ+������dG,�HfGE�qc`Z��p����PQW=4;qDU$�8Z#���c8nl]z ]ABfU��0��T҅m@cֽ+⠻�ሷC_,%㤊�����@2#z3z;` ������zGax@��X�)8pZ�����\Xq@�B8kA[H���Zx@tc~MA+2 `eRM#M���� Cx[ͦA����` ^ &@azLZ%¥ $������1&ʖNb6 maRtP% ]Z!R(tABB:H����a]Q:>i%h�� (ڃȁqtYҁd)Ҡ,e ܲAZB $������&q\le ��bhK̡-��ᶋ�� 8+|xA�,zG}@���Ю�������n'-aB1.$��-a������Qa X bk=ƢgR(4誃@hUG lU ��1�8W:H���������$x  �*xh[H�����"���@E]!��B!Xw\HB8 a@ahKx�����@ź Cĺm9R � ڔ l( $$«0DaPZ$,A0jD 8e:z!0&�6���lYjbҲР4(p&b^_u�eucq&�� (x)V< ������Pz��€MA�������Z�kfk)lw+ԸQ=L K7p˥:pFP ȰriJI}$BB 2�( J ���jnxp[7G4XQQ�����`kSPc%O$B 2àl F@/ �������6!(P���@deZ M 02*`) �� (Lڱûf'X@���[H0`kS` m RzƣV��Bq!�1+欻Ǡ%C[hNˎA ULۄ5@���`1AWCkð�'@  ��(:_SN'�BF 2�������ʂC�X   q6 ,u= %1���`���Rq���$쏯1H-L �����@(qզ �������ԥǠ.q\��HeXo^cX@����������@q<`҂òLA����,W���jK>e G|Y :H\6q uŐ1_����@xNk$�DucZu���,qØ޲QN1YV4n6+ HJ"� [H���X,޻JlUri��� ( Dm ���A!c%��������@dLS @ NwWXx@00hk ��@P)T ���e9 �$aV���Aa֦�#?h+� $�aY%L��+ u��!\xG1\ 6ŁjF�v5kZx@�@bB�����#< ����ԩ_Ѡ4h���% �ò^��8Z���,u��ڲW�������� ?.C0= -0ipF� (LDch[z $���&0jS����*z����������ԛ-L����Ș0A * $�� [; e\d[H����U찴)% KH��0e �����i ����Pq '-YL[; Mm4g/a*p[@U0�(NZ�����Ű,a�����՘rS p) ��lm ,e +X] �bˎ_@@qr¶=L[&e Gm,z ThFCk ��(B8mciZh����R�����&sk K_]ɔl) �������&���D4 e.Lے usRaYŞ`I$%�%X@�����B 6��X zIk,e ����BI)Tm=PH ���ikhNFQeB����PT>ԊNRrMf�������Z:6��X,a@�iYdNB�X4cf۵2HI$���mK@��������j |?pWB��,V0@vB'K�`1-K ��� qLȲx]Lڶ �%X`,e ����^4PNBX]q@�8ZWQ4ઃ����1�����Ԩ-ugz-a���@81M%փ�� T<Z^0,-Zt( Hj��>WH���BG]q]Px��Qk}�S*ҶE"- @�������(lڔZ�����% [&lm"eI1v4)�-*Ĵ`mc4Z+@ `MKH��B&*4b)X@�����`1<Q4_.6PJ- İB)5��% !a+���������DGyA:Wx@�`Z#�@l��%<'��bX�X ������Ca{X ��&2���ð( ��� 0akSB #vQJ @P!et) ���AaF1kp, AZH2uAZ8ZA.e �P @P%L ���ڛ>L6 n!h0à5@�XaX@$4R2���1���P6lm ���_d��ư,1mK@` ˒&����StsER��` &Aa֦ ����i 9[[�@ �ò����ҝ]y1y)T�����X4!��jaZ!Q@�������(^|)�@ Q7ֵ0"^L5(z������������T6m ,eI���՘4A����%6=Х $0h- �c`) ��[t9ZZLX,�K9HJ >ѭ $��$4RPh rL������ 6òIiXa0`ilNZJZ�����U}0Pn5@��0&� jSp`��cXa 6�`L˒&��� v.-Yka ����zMm/vL�e ���i 56zKH@qR�2�������%MP(aUmT.`0V2�Dmt*ȊHZq`8W$������B_# CvP Tt$�x૛��� LC%M 1,K �@bכ|�`+9 Z � (LDqeel+ �� v@% 0R`+Ҡ0( �L")V&����&\ 9r9:f$4 viD����������Ș4A���@\����T6\cᲄ�����QiIaY�`1,KٶrxM$�BV&� .���aYdKabj �%<p) ��i - BB-4jCTaK���������� ni&OT�(f9mkaB+P`�Q-7; &�� yZ W4@���%M,eI��`1m �Yֶhr%d-=�������%M��nlZ.a�����D5TjS��%M��. ��@���m/4����,eI�ò �X ˒.eBph[H�����):*Akq��Xfka��Gڶi].6����%L�JxR|@��������(^!��|C@ʁ$xM$��Mm ���Ű,i����PRp) ���@Տ4֠ (Lؖd[5G[ Ҡ0����,eI����T/|C� (]C �Ll{+�M$b$ m&l"���@(a¥aY�A/H��P2|�b XI$$4%<-o� �P������QiI�Aa tle"������� 2t� 0[t,eIX ˒bX(RX68a!2qV|LR!2,Gm0\D@Ble"�����Aa]mj0�IԵ%$Jp e � Qv�;nX0Q2��������@dt������"0&\!�a[� (LC„jUlX0��������A��C&r,-L �0&�&\VhkaP-KC�[ ��öY-JH` ے ����¡\a[&��ư-d28[Z@�����[K`[H�qE>PP,i[ ��������"㰤 (L7,00wHE%D���diltdž//�@8YZ@hL$@Y2YғD 'ud 4V&¤4Y D@Fle"��XLے % %@�HhL$@B,0ٕ7-L ��2���%@ˆ.h,KzK;Lv) � _OMR�2r&KP(4 p!$��a��@(a­H������Dp�iPpkŴma�������J(t(2t0�4'_. �����AaM0%=m_������ rIM$���0n6���a�`,\ȩ ōU/m ����3hŴmimas-a����PZ#�����PQ/h ���������A/me `Y$a[H�ö�2���@PBijIL$��!qn g˅1ٖ0`Y¤4X0��� wYeK�H$Lj@ D1l[J4M$�������`1Ea[!UzB6�����㰥Sѡ\´@hKBv8iYfcm#$,K@�Hh]lD����cض!Q&Da>&wk]@ٲ �HhMH@a`-aBƆr..���@Bl"Q,Ka,aB\l .6�����~&��@*vNm5G&��������`ÖNEl"¥Ka,a���ư]M&*4&� \l)mK2��J+:̰M$������@ [9D���� 2gcvnm"��0f 7xƕeasڲ'xdadd.76������p i,i%+2��Z貤f �( &0f Im0ŦPh !&�������0) C(4kMNeI�� v>Ћ8[4���������rML-a,� .6!M%M ���0m&pp&�� eI = EEg˒&����1l01lWaD&pyK�����~<������Aရ4f @P8&��XY^y[=] BΛږ&����@P8VlKaröI��������r4&'y@abNSn27H����� j`0 t�� D8k@Զ4���0AHhP 4: p0YI^l"������[6`4+oj4dY�$4Fm/^,f˒&����� /6bڶ4 aZ  pno��eI�eB��qI.I^l"�� vD������cڶ����Y8l����@Tˎ] Ҁi   n65Hd1[4lY���ưmi�����rK9ö 0�`1,[axyK0P]iz :5'T�����'Ւ&0����B t0&2���@(�����ŴmW` �<E{�_Ҏ{o8Y4A0D ����b-&2Pmov��'˒&0����J8VTqV $0I`br)Ci&���B x ���@N[:Mp '˒&I :F%M`�8Y4��XLۖ&0�����B C(�T=6'Q�Mp ���@Qm%KVږ&0P,Kf `7����ö f`itf7�^K-A<[H _.1��˒&02f n6!Mv� M`@Fl &D�d4./nm"SjD@ d����%)$xM6|;(,[eI�Mp*%M`�������Z ��aZޖa����m8�,mP��@(ဗrar`��N=`6|3��P,KtmK���aۆ ��@(tN=w\�������%›~;�� (ˍ$˒&1�������ʎ SF% P@ öID`ah7;� Mpgے&1�����cض @=V~k(;|;|hzỳ��@BVf ܶ'�.l����1,h F rifh` ����\w8̄,LD ��PtU(9vM,̺*@H:M#Ka ���P,Kے&0��%ف ���`1\4�Nb8ٖ4�������zeAZՆ6L`P^lk R2�P`3\B{y%h$&8ٖ4)N%MŦwe ʅo ,hE0 K�ɶ , T@8ؖ4d /sR[X���Mr ��˒FmK�ے&0�PAn2An6����e`����������J*Tz, T@�/BBܪctm{1Ku��bկT@d4M0{6�������@(ဗr fh�B ؁hے&1����%|XN7@d��8vcvI ^iӲl] nf"# n6�������mM��������P$傗rhyw7lŒT4e(ed��������P$o!�eb�����+LtxyNb��������J8BB ف ����������@ 喞K9��p7%Lb��X m�/2A3haٶD䲤I �h;�˒&12HmeI�LOf2�����X -Mb���������~z3�P1-I0AI3ha����`1\ pYi��J8;,K+/-4���������ʨw%|��eIr:؋Md�������ʉ ��,v ov ��PAj6XՓN!v+Cu@ TlK`[D؁ hR Z���,˒&1�.K���B irIM"Um_pH>H������6LPhdۍ %4�PlK����B D�����@Tˎ]A]Lm��������ʨwy{aXhizyN`�mI�amA0 Yii ��@q-i�6abf���鲤A^ A^d"���2LdM7-!oQA^d"�2:ȋ;F%Mb��������������� a8��`1<-2Q{%%8ٖ4䪗dd/չ֞ś#[aIln$b�i)Q<&0 D��eI��tٲ@������N4Io6��XLm8BIy ��������PRMD����`1]����e(�J:͝C׶4N d�T0���b����o,j4D¡H,DB ���Ȃ$#SafUp V"3M$`�����(N. &{ �����tL3nl���tr)������Z8] `~le1�d\c/h6*diB$6p����������%SZђȃRm&j / /2ٶ 5"����D.Oy Rn ']e`�����d"����J:M2�@_ޢRUd �Y8kVXZ.1m���d /2ٶM;Fm�������%zL"{Jwaf),����� Le&8ضa�͞"3�.DF��������`UD"#���"M&2������NjOR�p dۆ Lqm��� 1i ;'oz㢮 `���������.P0lۆ ����������4PB 'D`1\.ácqm8t9F$�]M`�@&U],2# &mn*0ضa�p7��,M&2�Pڇ22�����`a\ AdB],2Pt]���;P�j38 &]8(St]4X8ț;F*&&b������XLrE-& Nd�@quQ04ٛdd�������`a\J:���������_ʳcvulܢ @qnm3��D8l���@(/2�����()E1۶app,a� y;GvnlLB � f"E`Gp $̂ a�����tZDY84Tȭ)HDX8ț8M&2�Pl0D@ɿ&Ʉ)N.��������AI'}��� t9� tD!Ѡ^Y$Fm&1Pl[v ڇ;YRl!+_)������J:5Z8444D�8ٮ 0! ��'6Lbd o0!Lm��,䥜N���(Nm=I���(f6Lb����NA`"4}[fA^&J.&=w݆U^[7��&&D4�bea`Wp &2������� t DF~ )5Il`,,Ҷ&C����%&2���vɎm& Ȓ&1��ۗ �Y8Ld�����,6;vuH�Xw%"/Bq-ZZ@$HDTcQ!!a��M!dܗ L Z8K9H �, Tqrن%tLl- bi(oeM#W`F�wŜ1���=&D�����l m9���@qmS$FU,6!!9 .0��(Nֆj-0v禗߂���������� (/r{vW`�������E2-.$ ���T[D H76Uܸf$a�����brٲcrۆI �{M\ vIe ɾ,o7g7b ۠ZOUM) H���������Mr&Q"RA^M�TL.0�P y)p i*o �nl/* "dV&"���ParYP@R `Č��������KӦ &b2� QvqM�P da+1 Pat XP@Ą���͕"3�Pabde��0jmRbr٦I ������v&IT #����@h$_`"* _@����bg$*&c6  Ld�@% d,gm���J8E|+O]oK[^@ ���P1l$�����vm������o_)̀Ne^@ \a E2P 'ۀ2vFc�Q(♞ 2d: ������v&brنIanm+2$1����@(ط/I ����`! L5Qd ���͕"3����I&JarI ������VswɨE sm+$WZwf#&("��ParaV|.$2ف ����������etY&�������tb�,ep��@MP 'wOlιk[!žYHDl@B �����"BP '{I '{�e&1���XV_Av\"pǥ2Lb������rn[xHRl!,dor �P~Hdo2 "MA 6xfi)F ̂˖6:'^ZJ���������V{ -/1ui)  'b����������@҃~ ?m`���P<Eeb�������o0dv ) ("�" d���kB/6 "BE ������.@cG7 (��)Q.sWl���v0 `b;)Nu�����������E|\٤NJf*ɄP,J,)ڮ ���������XZHN������x*�`9\C@�����^eE6(do0 SapI �Jxh/d�[:wjob@�������K"���BK @wE"3km-IL>$&j2P '{������������d���Q�0ISr ��������) ���@h|S{[!",}���������D=.��������Pd@&V^uI" `%0�*d_@��������X&P �d_`@�4- m2������BKT nK8i , b����Ndbpۦ Zxhw73����@%;p vI����4@2���t깣͛`&D$0��*}b�����*L^,����`iz 21�������()|9r154 5P^2Q 0tqj]0p$tdlEc�����}Qm]!C��*d_@bpۦ Z88��P d������������^tԹC TM����Gؗ1չ喒E+[H d����@-<8P d���*FV,xu !lXL C D����ij-/Yt<hRUl%= ��@M��������0X/|\D9��������⚭�g��������������������������������������������������@� ������� ����@� ������������������������������ ���������������������@������������$������������ ����(��� ��� ���� ����� �(������@��������� �P@����� �����P��P��@�����P !����@@�����������@A"���@���@ �������A���(��(��������������� P������������"BP��� �P�P!P�d@ *��*H H(�����H@������P��� ��L�„�X�&(@�(&����`�0T �(��&��  0IA���� &� (������������P�*&LB����(�&�����&P�I��`���&JQ���� �$�P�P�s5$�\m�&a�(��RL2���� �� �(�PV0 �e����e�Le��C�d�P!e�L��2��C�� 2����I� (I���� I*�elB����� ���������j#������L�$���0 ��0`����C� aL2�� I�`(!��e�e�P����ML$����m�����L����(`F����(If�������@�P$��Q ���2�l C��`e��������P������l2����L�I��@�����:���e��e�0d�&I� �����s52��&I�1!�C������0��!�Tj!<Wc0l��e�P 2I�����������0dH�P ��ȀI��!�� ��d�P �6�����I��I��!0 ���! ����C���020��QP�P�L�u����`R��$ 0���0�������P6'dL�@�� ���@�@���0 ���@Lj0T++c��jL��L a��j#�$<I�T���0 ��� j����e C�������(!e�`!�� 2����!Cd �0 �$������ ��`��������ʘ( ��`Հ2�ɀjȠ��PV �� ������L2���������T*�L(������L@A@�`ʨ6@� ��`@j aPV������$@ �����2�(2Y2���`2&��e��e��0W9  `���T �L������a2����2� �2A2����&�a�`2WZ `�2S ���aL���e������Հ0 ����������((���d��0LjL�(��`2�2Pj�P���L�� �����������(+��I(P��P[�� �&�a��`�����YQ�e�� ������(��e�C0������0 lrm�a�5������&���e0��ula0�@������� �L�Uj�(�!C ����`0�0 ��&Z �1l�Ls! �!<I$ �� aH&Ð ����0 C�d � aA�0� a�b��(@V����՘d! T{8lڐ* a.a2HT+� @!<!� ��&0j0�����$<9 A @$3����� `��Mj$CjL��� &a$ 0�����0�� 0 *a�����&a2�P0��0�ˆ0ePc2�01%�0 �e�`6O< $<9L.ņ0��eePp��� cl�e0a Ա�05'g&a�!e82CjL���0\6���\mC�� L5�0 C0 #`C`C�j0P,C�! 4��@ )00����Axrf�� 2�a! �C.C �����e���!����dpAd& �LkeCD�`Cjd� aɐ<''a�(0OO�@! e@jm0 C����&a��Ld.�C �j@�\1BmL2SA̤ ���C�� ���0sL��e0ls<t2�0��������2\m̄! A! �$ I����T0� a����Pa`j �0 g&a�` a a0���P � � a0[M6jL2 )#Wl0\6d''�C2eC2=���&a0�(0��0 OO��0\$CuZaa�`��L2�j A�L( ��ef��������IP �����$e$ÔA2SVn2e��2�d�j3L����` IIR$�@ < C��'gVZ- e�� 0!L���\6eIA2p� �������A2 0 PL(d&�L`p�����00���ʘ 1'39L,pmCmHfAmHf��@$3�� |ِ3O&F&A2���p���P1B$3�Nm@f��A2 �Lp����������L`8 0�ʘyr\ ��e<9L`CPO5HfB$S$3����� �PL���(+`�&0&eTc &Sd3S@$3aR6e8L��&0��fN �@m!SG<%O$2Y����� yÙ 0<O0pFdfAp�&0 apFr̜H&2lҊ#ck{@2HfLZ<L�`×MP0a�3�`ep���2H LL͜|F��&arf��Am 6I2��Pep6F`ԀL63P $31'j2s1HfPL�����`&g&��0LL��d&g&�L2���"I><3��\s���063��&ə �eTc!����2Cʘgrk<M"ed&'�՞9 0�d&mr @mM=8@2��0LL�����d&g&������1'ϓmr^`�2jp$3�������(d& � m<I&_$���������`3C`rA2s':6<WD��L`rfesʞ|p @b#g��@s<קlD�Lŀ3399"L��&093d% ��e &093���� ~$P<LN"��@ulr!���PL(|ə A2���ʨ$z;dԘ0ə A z$BH ����@2|fș xyμn( d1c7=8"��PL������ ��� _o3~#I!�e̗=5�鑰hr0H3jGR-XAк8R"1 feh 9arf„Q;7<+7<:&Pd&@$3d<s0jf���ef2a&!Cy&'Ag&g&Y̘������ 3|x2ar���&k{fB8g.L`LN"�ԖdHmf�����PA�PV3( 0932̐3��� 39[NfH�frfL23��93&SFY s0�(��0C7m'eŕMa&2�&n9Ι'��� 3Ifrf$h9����IfrfB�@63s23���`$3dyL"��eqO5 3<ЃO-zr1��0L���eԍI!YDZ*B�����`dYLeǜ0⧹!)AIa&'�28<28> |4B�� 70 HI4Rd@.I��� pS3�28<jpx*�2$�Q32cTE��Pg�����\6W`B�`����H<yPk($B$I@L|3������@ �&yLCfr�� ���&�&<jՔo̙)>ƨ( 0E����Lf9REIfr%RIe&'GʙsfNd K@@DA=9PF��euN\oGc9xqxLЖBFr�&g&C�����`<��*ə ������e&< 39$px"4ehL͆ A!B94 3@0B#"fNŐ�`gLUǨm@ir+��d��TP5FUe3:Bdd1'uky����@ g&Lf��M>CcĠY`E!b&�`Wg{7F("��jT"0ả2rx0 y"<KM:�0a@9<yD(#ޢ@jQ�PFg=*\ZAL@��ƨ, !I�����0a朙�e(#�C3L>k*"`2QK>�ə aC�PF�2rx���̣K���PAU������N`e�F~��������@m,"?qT��Po a��0gOULKDpc G���`,;G�ar<9<��S_#TjƠVPD�A2�z yr`y7��P̙#�`��������PF&<IgByΙ �sf.F�٨€""�sf<5ƪI @9<2rx�ԖdL�0sL2<$9[fp �q e!y&�q5&y&����3���m bPa��0a朙�3 sL��0sL� 32rx��Lv>T��������|�*U8”IƠ€�Q#cU#�� C9 ��0sS����� ���/{"����C0axҡ5B��c5*vͰx`��CoQ5ց""F�`F����C����l䇡cv+a]X`Ú6&R 0F���d`U����@S"�PA9@9<s1rX[rDO�cЖQk<j1`tvX11 C!�1kG-I��!FE���@2R˧ޞӳ1P!�����j#g��!C-96Ül,š,g= J "DHf���0sL��ʸڐ@D���L _ã}"B�� 1.l38y#���Lx XYbz\L����!�lN'>1 9<2rx*�j;pٲ48�2r7�������q5z"F�@R;0so҈֠���FϤ99L@9G����9nZ"bb#0�&̜)Df�������@fyj2oQ� �(#9?cQ5j��0szCU>Zi&1I9g~��*X h�0aǨ[KaY=x�����T95 ��� 3糊`<TvD�Uf<@ɇ ÜTMb<xC10B�gFr����ec,bY rD�(#gfr������� eL�jKœy�sm(�@UcM��$#(#g�����eo^1 �` *RD1��^:�� 1Bn< Fy1!��B<u4(!Dz#!�0Vҁ�L9 ��)kCF4Fx&]c!Ds!D��� 3* 33B���*6��0Ft* ɈB���)1K!�� &3s��~Rv3$ϣt�ˠ�ٸ(����+(0j �@F-h������FUc-@F#95d 1X!@ ����������*jk$#W��@O���fg]VZ#cP�c*P("j��!QزCg<Z#�!D1ny ����q re2p1İ3Vn����j?Oc(D팪 � !�TPX�j2r��zՕfR��'[Z8 aq�ˠ+�@ňk!X\k!����� uન[Qk T$# ~? T8T8����qh]ˆZcd~*���TjA$#?�5~DET8 �!&)'!��Bx2! >P39<4@ xj���T9mkz&!YxPU������������ ux�� ]T���� 1�H1v3, Q4 1 ��\q>LmCF@Ly�nm;0P:n£k}�������>u/|T�BfRY12eqH�زH𐂺EpQ:B���#!X8p��HHk,Yfn=Y2c\k ����@\�@ꈧ҅#���H1Ƶ��RGB�@Zjc?���� c��@ꈃ+ u/)bX ���Haˤ#"rЃO�g�L3)C:P:t!���b1�b1 Xk �������T8�UˆP#C��0;p��� ���PXC���8֭B: �!k<ngc-P ��d���T8�T4;B: �RtXǣ4b1$�xC���@+1B#C��X(�L@PG\_nЅ` e�����W@k]q\#b1������Hxk:C�U`Ł2FB qA+"@ !�1ͮ+UP )օ1B!Xk+"TB[aZ����PBv+B4!6wkC������ "�����1.U:��:1 XnЅ������:k�PC]h p@�ˆ!�aĺp@1S-c1�q`X1c ��P/]�C4S-����\z:C-Z?�Pb-������H",,4w񫝆 ���XZ,mX_i�p�ˠ#1CUͤ+>Ƶ L"j0 pCkC@#:��0Z8 XZxHq\G`�1:Buܺ � ��Ef_1k !�!�aY]40#ԮHt�ˆU1kC�@ ��:1����@2E�$c\Xǐ1�����VZDZl dx}I����A*Fĥ����\8(א�� xq! ��c�QǡJ@ٸ0V{���R1c2ղgX ���XUR ����ԨUq ��������RG|׸4S-eBTX,C-<kC���QCb�P`b[Wz!b-h pC-��늀0VHd bңc����� B"JFu ���q,=tˆcaD])9JgpCDa`=C���0Z1"ふ!DcC_ѭ@T G@#:kC0f*1L_.5B��� 1^j( jP X*FZ���u|H�06CKzE ������qFu X5:FcPD��Hx]8baZF1F]C�F@W{c�����T8���Խ5>u �F07k}J=Gʔ2H ����@#u$Z1ƪ�"Bm6֊Hw` p@@#u 0b] hYѪ������`գFD\Aw+J9�B1JX�������@@<>j@ĵP ��1h67k|H�` 6;2J+p����cfQ/QG���@6����P-%:Ƹ1�eJz{vڽ h@a ��� Ċk0=0ejW ������@5Fĵr+>k +0 ,h ��� 1q/|��aĵe*zlw^x@��4 [QF\1�����@d#]륏Z CYx@�0Ƶpu](+8@����ak!C-< öXz�8> �P&1)~?RHGX��!����q���$c����1Exz!*+J3)S-< ��` @ ���V=+9dC? X,5>V$6Kb]I����,0A���PRiͅHX�� *Ƹ1����H#vW�bԭ<b, 8V _x\K dj����ZcFX����Pָ1Zf*ĀFF\k*%5��@T1���@1ZW|mJe�e���jԪ:� Ύ*@FZIA���TX-0VUv/< C-<ju<p#��j+F\HUz \B(F\ax%P *0��(0AA1Zhĵaa,=@ňkǂW�BH G]#Dau���BXqo#G\u(i_�!1C-< �����&����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/empty.wav�������������������������������������������������������������������0000664�0000000�0000000�00000034630�12225024651�0016721�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������RIFF9��WAVEfmt �����������datal9����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/empty_alac.m4a��������������������������������������������������������������0000664�0000000�0000000�00000012404�12225024651�0017560�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000��������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ftypM4A ����M4A mp42isom������ moov���lmvhd������D�~@��������������������������������������������@��������������������������������jtrak���\tkhd�����������~@���������������������������������������������@�������������mdia��� mdhd������D�~@U�����"hdlr��������soun����������������minf���smhd�����������$dinf���dref���������� url �����stbl���Xstsd����������Halac���������������������D�����$alac��������( ����$�� ��D��� stts����������'��������@���stsc�������������������stsz�����������(��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ���$���0stco��������������@������ ����`�� ;udta�� 3meta�������"hdlr��������mdirappl�����������ilst���"nam���data�������empty_alac���cpil���data�����������pgap���data�����������tmpo���data������������(too��� data�������iTunes 10.2.2.14���g----���mean����com.apple.iTunes���name����Encoding Params���(data��������vers���acbf���vbrq�������----���mean����com.apple.iTunes���name����iTunNORM���jdata������� 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000��^free��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������free����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� mdat ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ��� �� �� ���� �� ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/empty_flac.oga��������������������������������������������������������������0000664�0000000�0000000�00000021631�12225024651�0017654�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS���������{^d����y3FLAC��fLaC���"������ B�~@KJ£Sy~OggS����������{^d���%s,��( ���reference libFLAC 1.2.1 20070917����OggS����������{^d���Bt�������������������OggS��{^d���p� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS���������{^d���"b$$���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS�@~�����{^d���n5(�������������/������������t������e5������@������������\������] ������( ������- ������ ������^ ������������i������g������ψ������X������ag������������S������&������������+������;������cN������Z������͡������)������������������z "������V"!%������W",������#+������o$>������%9������&0������%y'?8�������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/empty_vorbis.oga������������������������������������������������������������0000664�0000000�0000000�00000010350�12225024651�0020247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS���������ۿ;����Zfvorbis����D�����������OggS����������ۿ;���r-vorbis���Xiph.Org libVorbis I 20050304����vorbis%BCV�@��$s*FsBPBkBL2L[%s!B[(АU��@��AxA!%=X'=!9xiA!B!B!E9h'A08 8E9X'A B9!$5HP9,(05(0ԃ BI5gAxiA!$AHAFAX9A*9 4d���((  ���@Qqɑɱ  Y�����HHH$Y%Y%Y扪,˲,˲,2 �H��PQ Eq Y�d��8Xh爎�����4CS<GDTU׶m۶m۶m۶m۶m[e Y�@��if0BCV���0ĀАU��@��J 9ߜYJ9Hy9s19眢Y 9ĠY 9'yК*9q`9&y9iK9HyRK9s9s99眨9Oޜ9s9s9 4d���@a)h Fb2A0 Bh:%qRJ' Y���@!RH!RH!b!r)J*2,2,:쬳; 1C+RSm5Xk9皃VZkRJ)R BCV� ��BdQH!b)r *АU�� �����O%Q%Q-25SEUueזuY}[؅]}}uaXeYeYeYeYeY 4d���� BH!RH)s9$ Y������pGqɑI$K$,O4O=QE4U]Q7mQ6e5]S6]UVmWm[uۗe}}}}}]BCV���:#)")8$I@h*�@�@��(8$I%igy陞*@h*���@������xxx舒h+ʦ캮뺮뺮뺮뺮뺮뺮뺮뺮뺮뺮뺮 �$��t$Gr$GR$ER$GrАU� ���1$Er,4O4O==SEWtАU�� ������� ɰM%R-US-RESUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUM4M Y ��S--ƚ $bjc R쥱H*g1^Q{$cA-)&TBc*RR 4d�p@,@,�������4 <4�������$M,O4�������������������������������������������������������������������@4@<@<�������<<D�������,4<Q�������������������������������������������������������������������@4@<@<�������<D<�������,<Q<������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������`!"��pH$ HM4eAӠi0M����������$MA �IӠi4"����������AӠiEi4hD����������4!E&3M"D ������������������������p��0 "��p8e�8��X��X%��`Y(������������������������������������������������������������������p��0 ��p(eDZ,8$ɲ�<D���(p��ASbqBCV�Q��ű,MEi'$I<Oiyi<4!hEQ4Mi*0MU��P��`��B�bYy'$I<OE4MSUIy(i,M<QETUUy(i<OE4Uuy'hEQ4MTMUu] i DOMSU]u牢i.MTUUu]Yi2@UUu]W뺲 PUu]Ye�뺲,����*ф @!+(��S0&!$B&%R RR)TJ*%Rj)UR) B*%R��؁�؁PhJ� �0F)sN"c9'R1眓J1sI)s9礔9sRJs9)s9眔RJsNJ)%A'9��T��`#A�R� cYyh$iy(&Iy'<OE4Uy(i*E4MUU],i0MTUu]i.l[UUue꺲 \ueٖ,ڲ���VG8) ,4d%��@B!eB !R ��p��0 �H��Zk@gZkZkZkZkRkZkZkZkZkZkZkZkZkZkZk-RJ)RJ)RJ)RJ�U8�?ذ:IX`!+p��s B)T1tTZB1$ZlsA(!b,sB))VcQ)RRJ-XJRJX1ZbI)Z1#lMjck*-c_dl-j #[,-Zk0[1>R,1\��w�D3$� � R1s9R9sBT1ƜsB!1sB!RJƜsB!RsB!J)sB!B)B!J(B!BB!RB(!R!B)%R !RBRJ)BRJ)J %R))J!RJJ)TJ J)%RJ!J)��8��A'Ua BCV�d��R)-E"KFsPZr RͩR $1T2B BuL)-BrKs���A���3��stG� DfDBpxP S@bB.�TX\]\@.!!A,pox N)*u ����� ���\�adhlptx|������|��$%@DD4s !"#$������ ���������OggS�z�����ۿ;���f}[� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/gnre.m4a��������������������������������������������������������������������0000664�0000000�0000000�00000011642�12225024651�0016400�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������ftypmp42����mp42isom��mdat��libfaac 1.24��B� 2�G!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#���mdat�� Xmoov���lmvhd����El�_���������������������������������������������@���������������������������������iods�����O��ttrak���\tkhd���El�����������������������������������������������������@�������������mdia��� mdhd����El��D�~�������!hdlr��������soun���������������minf���smhd�����������$dinf���dref���������� url �����stbl���gstsd����������Wmp4a���������������������D�����3esds����"���@���� �� b��� stts��������������������stsz����������������� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ���(stsc�������������,��������������� stco���������� ����I����� ctts����������������������Xudta��Pmeta�������"hdlr��������mdirappl���������Q���free���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������"ilst���gnre���data������������qfreehdlr��������mdirappl������������Lilst���!too���data�������FAAC 1.24���#ART���data�������Test Artist����������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/has-tags.m4a����������������������������������������������������������������0000664�0000000�0000000�00000011764�12225024651�0017161�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������ftypmp42����mp42isom��mdat��libfaac 1.24��B� 2�G!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#��#moov���lmvhd����ELII�_���������������������������������������������@���������������������������������iods�����O��ttrak���\tkhd���ELII�����������������������������������������������������@�������������mdia��� mdhd����ELII��D�~�������!hdlr��������soun���������������minf���smhd�����������$dinf���dref���������� url �����stbl���gstsd����������Wmp4a���������������������D�����3esds����"���@���� �� b��� stts��������������������stsz����������������� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ���(stsc�������������,��������������� stco���������� ����I����� ctts���������������������� #udta�� meta�������!hdlr��������mdirappl�����������ilst���!too���data�������FAAC 1.24���#ART���data�������Test Artist���----���mean����com.apple.iTunes���name����iTunNORM���jdata������� 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000��covr���_data�������PNG  ��� IHDR���������Ԛs���IDATxc|�� Xo����IENDB`��/data��� �����JFIF��d�d���C�    "##! %*5-%'2( .?/279<<<$-BFA:F5;<9�C  9& &99999999999999999999999999999999999999999999999999���"�������������������������������������������������������������������� ��?���jfree��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/id3v22-tda.mp3��������������������������������������������������������������0000664�0000000�0000000�00000020000�12225024651�0017226�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ID3����eCOM��.�e���R�i�p�p�e�d� �b�y� �T�H�S�L�I�V�E���COM��h�engiTunNORM� 00000000 00000000 00000000 00000000 00000045 00000000 00000000 00000000 00000000 00000000�TT2���I Can Walk On Water I Can Fly�TP1�� �Basshunter�TDA���0304�TAL���n Water I Can Fly�TRK���1�TYE���2010�TCO���(3)������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������VBRI� �d�bۑ��!:����@6λ7Ϻg7׻Ϲ,58cZO4ķccmY*0Eλ6p7 Ƙˆ8`h0h088�Ƙ8Ƞ�h�hȠع̻p˵}X,˻fh*e\ phƘƘhh�ƘƘȠ�8ȠȠhhp(7����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������D�����K���� p����.��� ��%��I� B2|P��m�H�PЮ  קNn``0�7(}xD!����K���� p����.��� ��%��?ݹVjƀ@��1V-܀ 3�o,ɿ@(kv<] �/DB����K���� p����.��� ��%��?Nnc%���� �Wy|J�B� [c�P��@��@��@�d>c����K�� i c�$� '�\=P�N8] E#Lu uT;`;W@RincKDdnt�~�ƨ���`=��l���:dp�ft7?AۑէV)GH4 -Ơ,扖"&&& �&&Gdʣo��HA`�),�L/�� Cp�)FF#�!`ƢPa <<p S$-+Lf@`;2Hd!k��'�ˠ@�)� � C��y&4[>mܤ A�u{ T " [Qb縓n'1dZAv���ƨ���(<��d)A%apr2c`kQ#��@�D"M$BBIłHC�Aa)h])dN__.a7?yqcKd SȚdCM dM?KYcl mg o1J̰~zeG L Jx@iɷi@3G ^BCL4L(b QVh2Q[:}8%`TȺ<cܐ\7TLr!{d2SS͛zey=~vwW39u=e.d9%}�PPfZ)ɟqXAK�� )g ix֖J�,z]N Xp q+Ed i+H?rUbFXF @!7K@tI#$^s^{uZfR@�VANPB6(�Ȳcbe2CؠU%lu�F3ޛkC:ϲO+lo.WevI ((,xK/)-)F!tҮ̿azLPV1t9d{O](TˉUݔ]A^+d`+h+E ꁬ.֤e gB}2`i)iN"G_P?VB]0[u!  ,4ظ1d2/=/I]4(IJKd yF,MyeǒUL$*v1"wL٣qf&܂.IdMZz.DD n0`g`7fBbrjF_XIÁ_,<E2}90T)&}׽>4q�,r&@'vek�F2ɅP߁#q3R-vB^Q2v,'; [O !iUxܪ#ڧm.BNV@|=`IФ@~&{;3/) 钕mH9JaNQ#HZ:@�@ V9.QVNOilMBCS%A8N"q9/ JDxד8W$DnFuͶYb317]Csmm'̙5"9 o2 $i BXi Zo 8ɠU@JQ jxEa?41 TJ`\[a aV6,�(1[^ ZŪV.MYe67圚xLgw�A¤3Dfgw28<YB627I :8,LdU^^Vd#UVS,<IzaS/S- c&IZpPaH۾ !VkI)AҋE9phਛ?ݨH֢BJ ʴkpJσä]2<LbOa齋em=50Rv[@׻вM S9{HGBٚf+ӝX# �i< @L1_t4\qf/ \hONꋇk+gU^K|]B"b*n~ߥ[/AgFTݫ/tY>C8=9%P5ݷڇ95V~RTI 1(|U'Wl)Y8 }Wf5sJ< ^V_ d1(S3QG[W„I M ZEZTMrůVkeXVae쉲cEoy C*nQ :Z]C�_8 2)HN5$xiP26 iBzQF*4{_.Պ‰EšJS}pW^uE>fSj+E讠mt u `OEҖQ+҄W3 wmj7m  ZTC-8do JSd<i =a@Q5�:;iR'#ȵ$[#*44Iأd d@<CpGlz?4|2D'%-(tk!9F_�a:#ǎBm2Uq1ngbd$^ 2>^<կ'Gĵ2IY.6MnH$AפQ4(H^7]dnf\ OVmc i3ו6ѩ(t/\ljgYj*fRյ5 k/11 ߯ qU3 ķzFŀq@eȭ.tfOrdLrwp,2g%_%v-5aT`lĪK@ηD +5#bY,fE7Zxq^ů֝=Yֵ=5^1-SFؽOLb )'CFdB)L`PL& j.z/LBSJ95H.Iı3 [ZS7LKq[LN1(SX 6(Q33zR <Vxk/ )_9'GtO|8mx<c5ۖS_�$LB5dy�sOno@�Ɖ:�)3U]�*r++PT0 C`(XHA% \ xTMt,f $bCt0p4 Y̻{L0=aU$EMxaЇFA"xKM˟F'2; RlRw9ͤa^PQ- e:.ԍ׃g8͇ʟH"v Nv}7*@Suڵ Z=844AӹK!.ݛ*Pm6q TPQv8PFbJ0"bl3TzՈC$>G*@cl~eA [X`Iy"M؍kHRSN{kgV.qpMGlrM(QEIe۾Ԅn{SnM Z^͛lasv1?s -1K)†;$KDJ ۷mﮆ =0V<�0# !FscyԞ  P6iFb|Qv8<aa*v̆m۞R˳2\nPv]l3_Y%IWZԹf+M5;g ]~!3SXs 3ݟfawׄ.`ѿbPǣN0&tӳw<-ei3E#&hԚbUdW)NO-Nj O-jW~k 21*=fl.um~j+Ƿ)RG3}3;;q?5+4CaͺXn[ވ"m k$I)#�j:a5dO�GS N:iڽa&5!Qeji$[351-F^RarXns4Z;-GCR8p\3kf{m,^#biR_j%InVF^ɮDO~ێ ,X3fnw�?JKS,Fp%ZFXH]a`RjKS:Rq(LXї/a-مM> P&\~(=P:,ZF4:Xa-^Cڎ1~*2qYubP� np=7ff- ! l!3z X8 {ae˱B`X1RQTgj[@b<xKT(Y8N⊤̐ 1m`z(Ur*(?kY-}O~[}hqC)iӥ pTddOqWrmF? D$ᮎIP sь[R3%C˒!ehpdUb 3%IQQi}ԦpQco$&Yf͈IKGF\ϘBIn0|@ q Z+a2�Z&d?MT Fh aTIY:P5& P"QɜfJJ pHk0 GU.Xd𣧞$ZqR9\8 0i KlHYTʤ%3k+3 4hvӶFFBhֳtxŚh6 MH}7=6aIǨ[X2Oc<Of{' @4e\`x~Җw*\s*);.cP?f?ŝ4l DbK=}!FE9o|$|6γ X:܉J,8ˁǒ,YIo(ڪl!NrTb<}'}SrE6p Z'bn$ABWS)(kXh sK*>NG$�j+2j &iwAޣK/]Y,2ܷouRENņln 2x$S&Žƒ.rxqobV1/#UJ@szpQ]I됣$aJhx)EHTawYeZ*3WKJFߎ1 Y~'�}YEMވ=zDdAC�LUS/LZʽ=)!U=3j9j[q]0gAG@eg `!44e#ud+'ӧE0WԷC.Iޚ(ˣ l laP4ijBˇr•#RWQWdȕdH$iߐ @Պ%Bt3 $%z|<Ǩ2ɨ4\�"DIMM-ąCǔFT--h/RHZҸCQ&%;ŻH"x^U֠q2C̖g(<i+5콡 H(RZ - Pp>Oq"\IKĜ3j 49*\]5LDp۹#MYS^҇dubh g#x;*H# !F]" OLѷI֗||+k:%&<!!P\#}0h�%�<c$XFҧ!$F<U6  z bay*K;L dl݌Ojc^qӡK1+Ն5KlruѸZV*®*V" mZ�Bp YhDü%84(D�e+Lhբ$Cw` AAf9\1Nߵ:z �NZq߂6Є -B?\d[1�"Mk,ȁHe}IW=5b()"`ʢ)N@9#yBޗxz( "i]XE_O1޾` YIl뭇ș3qkT�Def5ljʡB.XOY�JYͧW*-9gXmz 5gmL;$-: J$UbX΀ ]uıiOG]oC @V% KtQ$]gBk)Tc,-LFpOm. slG:Nw$kkoS3(ಪS.tzOH,]H5 iE1t B㇈t8=9vY,M{5+(Q lRXZ}`0m} HlE0kl h4 ̈+taglib-1.9.1/tests/data/ilst-is-last.m4a������������������������������������������������������������0000664�0000000�0000000�00000100000�12225024651�0017755�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000��������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ftypM4A ����M4A mp42isom������3;moov���lmvhd����1'*��D�,D���������������������������������������������@��������������������������������0trak���\tkhd���177��������,D����������������������������������������������@�������������/mdia��� mdhd����177��D�,D�U�����!hdlr��������soun���������������/ominf���smhd�����������$dinf���dref���������� url �����/3stbl���gstsd����������Wmp4a���������������������D�����3esds����"���@��p�o���stts��������� ������(stsc���������������������������,Xstsz���������� ��������������������������������������������������������������������������������������������������������������������������������������������������������������������g��,��C��G��=��?������"����*��+��1��b��U��������[��9��������������������������������������������������������������������*����������������������C��$��������������������������������������:����y����;��������������������������������������������4����������������������������������������U��������4������������������������������������������(����%��������y���������� ������������������8����������������������������������������������O����������:�������������������������������������� ��������@����������������������������������������������P��<���������������������������������� ����������(������������������������@����������������������,���������������������� ������������������������5������������������������D���������� ������������C�� ������������������������������ ���������� ��������j��������������Q��,������������������������,��D��A��s������������������������������������ ������5��2��{���������������������O��������������/��@������.����������������������������O����������S��#��/������������������8������������������2����������Z��-�� �� ����|������������������������������������������� ����������������������������������������������!��������~������������ ��������������������������������������������������������������������|����������������������������������������������������������t��{��x��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������l��x������t������������������������������������������������������Q��������������������������������������������������������������k��X��M��u����������������������������������������������������������������������X��s�����������������������������������������������������������������������������������������������������������R������������������������������������������������������������?���������������������� ����$����s������������x����!����������������������������������������������������������������������������������������������������������=����������������������������������������������������������������������������������������������������������������������������������������������������������B��������������������������������������������������������������@����������������������������~��������������������������~��Q��?��U��������������������������Y�� ��a��q������������������������������������������������������������������������������������������������������������j������������������������������M��e��z����l����������������������������o����������������������������������������������������/������������������������������������������ ������������������������������������������������������������������~���������������������������������������������������������������������������������������������������������������������������������������������������!������������������������������^��!��Q������������t����������������������������v��|����i����������P��_��������������������������l������������������ ����������������������������������������������������������������������������q����������������������������������������������������������������������������������������������m����|��w��q����������7����������������������������������������������������������������������������}��������������������\��O������F��M��7����-��?��j��t����������x����������A��(���� ��P��]��o������������A������r������b��������x������������h����{����������������������W����s������L��������������������q��-��1��K��Y����������������������1���������������������������������� ����������I������}������������������������������~��o��y��������������������������������������������������������������������������`��M����t������������������������������������b��m��h����������������������������������������������������������������H����������������������������������^������������������������������������������������������������������w��t��������������������&����������}������������������&������������������������������������������9��������������������������������������������������������������I������������������������������������������ ����������������������������������������������������������������������������������A���������������������������� ��������E��������������������������������������������2�������������������������� ����������������������}����������������������/������������������������������ ������������������������������������z��X����f������������������Q��b����+��{������������������y������m������������������������������R��������������$��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������R�������������������������������������������������������� �����������������������������������������������������������������������������������������������������������������������'��������������������������������������������������*����������,��������������������������������������������������������H��������5������������������������������������������������������������������������������������������������������������<����������������������������,����j��q����������������������~������q��������������������������������S����������������������������������o����������������������������������R��������������������������������Y��r����������������������������������������������������@��������������������������������������������������������������������������������������A��������������������������������������������������������������P��;������������������������������������������������ ����)����������'��j������������+������������������(����������������������������������������������������������������������������^������������������������>������������������������������A������������������������������ ��,stco�����������%��,�V]�e��͇���>�e\���n��$�JA�q�#��x��.�U�z��ǃ��E�;�a��S�Ғ�X��E�j���|��*�O�vT�a�s��T�5+�Z��0��� +� ?� eW� 6� � J� }� $� Je� p� � P� � e� /� U9� {� � � O� � :� bX� *� R� R� � � E� k� � � ��*�Q �v�����5 �["����^��?z�e���-��$�J�p��^�p� �/�UG�{��7���;�`��}�Ӡ�!�Y�E�j��b��udta��meta�������!hdlr��������mdirappl�����������vilst���nam���data�������Intro���!ART���data�������Pearl Jam���Malb���Edata�������1995-03-22 Brisbane, Australia - Entertainment Centre���cmt���data����������gen���data����������day���data�������1995��� trkn���data������������������cpil���data�����������covr���data�����������6too���.data�������iTunes v6.0.5, QuickTime 7.1.2���Z----���mean����com.apple.iTunes���!name����replaygain_track_gain���data�������-0.67���Y----���mean����com.apple.iTunes���!name����replaygain_track_peak���data�������0.45���]----���mean����com.apple.iTunes���#name����replaygain_track_minmax���data�������82,164��free�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/mac-390-hdr.ape�������������������������������������������������������������0000664�0000000�0000000�00000000200�12225024651�0017341�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������MAC <��D��,������� ���nd��'�� ���RIFF*�WAVEfmt �����D�����data*�|���L~�c-�d�= � �Yk���RJ�nw������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/mac-396.ape�����������������������������������������������������������������0000664�0000000�0000000�00000000150�12225024651�0016600�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������MAC x��D��,����������z��������RIFF$ �WAVEfmt �����D�����data� �X�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/mac-399.ape�����������������������������������������������������������������0000664�0000000�0000000�00000000254�12225024651�0016610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������MAC ��4������ ���,���(�����������fu3 qi��� �:�������D�����������RIFF$ �WAVEfmt �����D�����data� �b������b���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/mpeg2.mp3�������������������������������������������������������������������0000664�0000000�0000000�00000040000�12225024651�0016463�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Xing����%�  #%'*,/2479<?ADGILNQSVY[^`cehjloqtvy{~���:LAME3.96r;����.[��$B�� j����������������������������������������@ @��'(Cp�&D�¢ 8ke8/L̜ "N�@0e@9\E� H71 �P`]X hMCPP j00Ч~@Cpŀ` %B @4S@,<5xI)0ceS &LR\J JL*lR*F#R�`&_t٠&sf)wRT`Ji-AYAr7w250ű7;ۿ>O <nmԋ~7鄇ZBV?{jl&yD?V"s.rO׮ Xp&:` tUn'0[ĞOV|(D冺ή9-T/ i 5vK9K�( 0T,~e3:N57k?Nt_d - BZퟱ?\{W9o̺9?N�'8 `%J^`kj!H@vVvo>8`D3ע&TqD)o,J\)=5k{;t HO8ӔC\A`,xՙ @UFm#v2|&M4?) ]uּz@M6 Ǥ']@U� + mdP iyǡ!zXֶ8d{\9#kh c]:zƧ:LU8BPb^_֮4.ڎA�Yw5[2YFԮ'/�!!$s�0b͞0 2Az9W5"X1ȤE QϷQ0A 00e0 xE1�h:O+/^I-KOSSCۖ2R V/¾1)ŰR Gi|"<oUc2i>~  Xf OtrARг$gK�ō#VAU{P40 P�FXv%f]zB֦ڼ4ˠXGb+skLdfU6D2Yz P{  `�xpRBLQv3rS2 LG]�aܕ0 ~�x|˝hwa8~q"IEsX.uܺm ob^Qqdc0 �xxOC"m0,1ϒfT/* Z5bw޺T^$(9 bς  H�`LeaȡE#Ե:4Ѯ0+I0 �yFdgt�϶ZYv5684*0VhT:HDUH=[( 9֩< ؛@3M>  ˜zF$zO7PB04+SЊ RB#pN0(xd"!Foqx6@(8<l ys jqJ7GRnՀMp.m0 I2JtM]:1y$;wiڇKCyGLg (M8]K>%E~**@F F �"V0d l6۟" qW[$+<4)<\)F|3&8d&ҫբuT4!Ee#0@ * Ls8L.~L} z|9ҕ٨;pXDd` tB2#x |: cqEEh)3WL{oЈ,dqE@Y`�AXA$6X@a&(^zZD& -Z'!�fV|'Z4Wu.-{*�  Բ~C I`&r鿏+ѐ *22@  ܆LM2³Jqor0DRf7(66�X P2>hL7 � VJZJLij2tEPdqqX`"c8#6AAzV I@1 -�G~n'b˰ñ$;0J'f'{21oҌC\PpIU U3}e�<{ '{f{r8x@C^HnvL]f*k }qhi*j}iF$><Zaq$Imdձn<P<W ٖyE0*^@o ήa v*WuyeB~Iу"D(_j\"B@bp3 nѕOue02{ X|mq7y,ˊ]u7ԙ%ՖԅHr % 7UøkE 0  y%WY P g )yP0Q%LsgJǡp<&BMRp2H ��HFa'w,l.'+Of3*_=xؖu1n^C00�HTˊO3'6G[(gu=H5H2,TJ%e* :K&(ْF70 � "8 CL}Ž@0`e\8t14M*z.�pV8б$90�34¡j)uӎaz%6 %dNOGH~mJ=BWpFU@qŔT  � OW'I4כL:Dv#6n%a溟jJ:t0��N` t�@d3 (M�&ֲUqtm3W@jF<Ea #  تzJb}J9$�)pSm]lR ЯEE0^`DZTm�T"6t�8T*RiL!U cԭ(i8p>:;UV@ SPjVxؽo)es53FưFOoDn},>g!nŸ&{ޣ'֧!R i<:3f!P0<$pAaр(f@"j0TЄI":SCu݈H1qx."tGvwC:Qn?Fw'$sE2N6aWt>ШRbuajU�1@iټL=cH�F͝׎zآoJo*-p�RsjU[�Bi Ca˶[d�r%aqBHa1LEg"0^y"> k d{2׵Ö<S@T T@BD G m},& �"є@IX>y:ef9<efg}Hw]ݱt0 �AL_c:LC k|N=out}%r2 ]Jh�8�r\@ fն@LqJf6Gǧ3܋]71ٞڷ|]iA%i`ɴa$ڑLAFx~r5IxĂBVߔx'̅90 ^xF=�p )JE[ p$d ĀQAU S6%Ldd  x̑�q9]bYhB23g.60-80 xsn[2\m*V/<$~6 #5od (mqo�*U 50  @F^ G1gPD䓜 k ϗW\�1y`pb¸�z1VUHmCc e=@JyX}U83I&q_rLȥrT`. Kl61;aqn)YوH:*mI@ C"~n�h.#|gY7%Joťg h0$B46$oPb"{"�Ֆh�]ABR,:hy +^C9nPXPYnŅ7{8Pz2e0�>V{h� pX�`Bxy1w,&,cZ4{BT�V{#୾d0 HҼ(+>8_$-a}D-l7 =Ƕ'7UEw=/Y0 6Lϡ5FZ܊r @]uv8`4*nKn�1@x[iQk)nx0;@G.%[^d"> hS9:q)0ic %266!6pMr7@2zL=҈ a0"ɓ[)@ �ɤ@HHC9ٱd_lNG1,&Ol�"^_%/E960�b pwb�Z}Lk եe6곎6XSKQpvUE>,M<~i3u�'<@d0 8{ h0S( iv {C3lLC(T*'|ޓPu^ŊU5 iR68  &C }1N�J҂{#p3 5WB̋ �01ryqFLI Gƹ$"`d0(}ӽA,r! . @0 z8`Ҿ'B US̻܇Z!R,7~ ŻeOjI^�yB%,<dNZ @>`ĖI*waMW>,1[xTxJ2[te0�pڸb�>,̘& b &vqB͙\\qT4%F,hYMBwB*Ip+0 Dc@՜}hqلh*'"N+YkW]aV~(7 ,u�k9&9N)0vy"dY#O$(Laޞ_UQq+۰}e4ynjI1WK Xhnt  x�ƌ,VKm7Z a Z%a_:7B׀"3B0 J4zA"HxpqhڙhO01wL}Eo{qX&ȸYm0 p�FHfr@ Rl\c+ 0Jxگ{6�;JU+# "~Wi$C,Z tzI&�&0[cdz<J~w#\Zb,E60 t�Ig 9⁆*e]ʏ_r64̈tvT`ÕԔU+ʂJ7źOi0xaR/ob1PUf1xVuak^ov!2tIY?c\jT}gB r-0ta|͇51~wFF-ϴJ5`s^=H$BQ& ֮.Y�y]ri0Ɣ0^M˹_[Fb!iהp uJ/ԤYGA a6+èk�UbR-(~&b9\0*yY}2{d)Y>`j{(^HDJ p?L&SKB he0 -I�Բ5@ƪQ*jE$.ajHn@`S)Xr^U�@��YRb*`&^l�Ω&͢2VW+4X]V9+o!zj['%4RA2D#Mc<5%Y,~V1~?{_?V}6У1Mnyuvyß �fA@” A;8p&bޱ�XF5"i_�߇'ȪnxDT<N37'ZP@BT;]<g>i`¡Z%uNn&X6W qi)ѣ̝Li hn$k-hsBh@J Rv1̥`?'j0fM5ϟ{,;+Z� 3=TmS(@ESb\P* d�B)ZktaѦSOH'hE[Sj eJ֛R>L.@!�OeԻ^&/~ZM/L 4cV3(8㷹(*Бxq�@>龊 e�)HyXML(9&,So♨a\(e'[ϒuwD~\s�kՀ4RrO0R+^PE0|""ʿʋo#b8ψ~AO7cbz95EI1ۗo�=# ;Q$Ny }q^vk0q"^(Gjd[�;q:7#I_ߐHXfɘT3‡YQq95!0b.|! 1z_݄;9SA%C5Y w6PR01TjϾpNHɏT! o!8bW#O wtle�jxA=3 y^ &nM-Go~oAEs9v�:M*&3Q0A<,\C|_Zd ?KQĊξYc.[yM7g,{ª= .,40_r0 ��H' ޭxtvTΨc|�,$ƊX`GO;�@#:ROڌܳtY5~ Y�gtT9%(@!vU.BtA�'p&޹x�-s9N\ϋj{H֥>)Ts{j;ijwx,"kzP<^ƹ D>9o,dI V7 %a%{Z絨ޡd,/ì0XP+4!:r/_>D@`Řok T�0(]IjAOZoR+�Ӏf<}fy;zչ[jc fљ)@^RM"Vbr1<dbv  > !5'M܎oeKfܮ WAiވz2yjIۮĉ!>l6 0rc\yRJ N.S:d/@g±a<81�y7Kp!J]vU&3@�3^~R lTP8bd3]w ̘ Dcؼҍ<Mq<-Z"jFn{+& &;PCH�ͯ( ` d,J?5a %M7O^{0Q^PGN0%�Df/|"_҈G/}_-<-Fs)j� �0Y^Yİ fzFчLQ/�џ}JԡY %nPNPBĵ�.O@;}I0 4TL`F?@) 7`+X|S#Ҁ�X8`= c 9^(GnYi4E2/C:gey`qh?� h`0Y TĐb*�@e7")S7ᄋMHP '1JF d�;l0 S~i#FA0/ uf{vsCic}kk;!Qd/ ^iװ_}7<C|L⒱l�2U0�:2T<] R�##Wl. c�|Hl)_W'q?oп/IY �0 ;DڒPhdф? G(ʫH&P"";Wf~eUk�0ZG^QGS # EH5Q]kcg@ o)~oFToX]q50�0:3Ҁ+c( M8sѓWh p# Bk[oAF 2qABX8s0 8R�4nn$@D.`( @oBo`C@?PȊeXozV`0�fHep X%]<SF?섾+T ¡* ; $K֝payv1 `0D*e:�I+wc^)l\I9!֪�rH�0*^`Ĩ:982שּׂjj\2u3\mvjb\;-Cm}QNB{Wzjv#"8:G0 肬�(:@DbL|EQJ\]%P&8`e8Š.oƉU�30Gb0  (zD8tIW8퓬yf}o8@bœXyta}%0 J^2R�ђl�-@hdYkYT<s<=K@" ?$Ue¨5aTD�CG0 nV X8N~hFAiNҚpZ+!T(w.toT`p Pb`SFNI@9[K30Umz4Hvn$a|1A&k{vWI̜0M #nusn($9X7PFGo{` oA,2Viʎie,3I4VIQ3,cՔnnOVz֨ߴBp8- mO= 1ꭰyqirOڕ*32<R6i;p9*VХJl@jH̼ۂ0C%``_$KBwf_zwA""Q:,�lnmX~*GfpmH!Їq#0i+F/s!O=c!S`gruکWI=֨O ~tm/S%-09�Jx(n2MTFt>Σkaٍ֠�P\TPF{?=</ aFlؘ0g?E sqU"H:ְZp0HtCX/ow;7zGN=2{>$5>, "FL՟B°˵0 �Kƀ?!P 򈉝43!a�ԧlOrg�aNAw;)S9z )� ,ӨGY425ϞC:W[B~0 RH̐, Yoq0nSQ25S烥GIVTZZ{?L+RTyTi&6xJD<0&=al08 ֭Xq53*qƞakP&]Ix˅(TJ)_iJϦ$$)0|Ll  O@�F.j?`3X0OhAD }?�Px P Z.X�#j&,~C+*^KZmW-q;Pgc>ú~~YŶ}:(tSޫ-<܈jA$ M/\I?f*#`&x�JWG/}xu:]XS="1cKW%,F_bx\vJ@ʏ_fu2 DgVE50UΘwTc}W5m,E1@|H_mVÚwmgeяPib0X0�4sPd q�@3Qp,Ep#8 T[a`a1 i`ŬZuJ�&9e9@et0 EQ֒VfHUX?/a ^^N8FIUG' ץ™ͮ9*oŅcW0 0EQ{H1'F$viK瓖Tm2B¬u׻;VqC2Y  A�b% CrVrX+" AE {o0� �HG@bI2fG#,K[R^!Z& yFlU ?(,;-)s䥁&0 � Ү,E*|�iPc9Q @ɑLy>h_yj  �<1wOtBRECu3@>:>HRy}0� X,ܲ2 'Ê~r[_MXZx)MeWȉCՁ1*o=Хb0::Dtq[g=&o S*E=J;ufPBWj.@GT8F 1][ga (  ~8<LL}b~SHBWJC`T!$M~�0f EUUZ`"]m&L[u w1Kc{5K\uhͪ@P;9<W0 �� 0k$ô(u˹ъU7V4%|>0/h2Ě!3؄  �Ip86Z 7okyJi{3W"ov?ahN0 8 H0� Cc3W;ngYOe4d<<R5n'܌ hH}UD`&^ �>�9qVgWJi{zgwȴZCHSBԤ,bzer*aswMnKcz[oTX-T+z¦CyK)I?o׻{_3/@Pp'^x� I<JpSV 3$%8V>"7tG&f#l~ob~Y⮞o1 :c3D}Z6ӱы+qY2׋NY=5LӬE;;R1^~NhRnXd(H�V͠ښEc&h0�E o+˖sjZ,y_"IsΓ̾_&T+YkPԞ@40` 60_I7"گRzmU6M``SI'v㧾yfnk'-�$;4£0 T LO @,Wz~g9W:O llFs %CJC| Z pBUD R H L[vHC"^*!5L(JH2"CZ:n0� Y �I\O$ r!TiDkCu<7dN(R Ej1yS>m=HΧ%澠0 �A,QvB.r!2pL�&)t `jGDJK?mp uu{3  �{0B- w"@?vU{nA2‘R0 B�C,ݰl4un_'% />(DhIWJѶP |K4  (C ,9V(q(mPx4aʣrB0� .�,Z4 Eҽ3J <uFȺA!'JDZBQ#eVwlԏJW{0 *� 08 e2q" 4%I^=!j`ANvuV$)6+?]  g EJ_?v=vl ;~2u ujjLDzEԡA 0!j@EH@>i6 9VJ(YLݔd FVF5Ĥzd7t 040 Bc @V=|֓()[ y}&5F;~)Ez)U?jvp' `IC0 PF".m8o=^7 hEvz;V>A�g grXU@�a(l�06Ld�~"l.dA (*й`d {9*P W*!Ŗg'-jÄѾ; �zDl2B ,6oWl"S&B!<>P 09"T@Gn\pt,rP,Xq">hu0 D :+޴pBB +VM0 `E$x rmfL m�*&{+ x4{7ǰls䨤J0Kho_S41:6C>l;렚EPBP@&r5[ CPZ0 A'qZQYyF m[r{C/M_3'a+ih6B@ʵ8/[&#L0Y""HLȋ GLEUSiF#b0#I798p be$?[A`qq=00 8*@Ftܔ9?0. ,l BbیȺكK% }T.L1}s  n�`FSP"M]˺ BHhɤcЎa0%*-0gFe7-� Hru!L#dg!rפN�r}S Dz\@|J0 8:T2L�Ae&u$$H*Qy$`&4)$ki-GBwI`*)Cޔĥl  V�0F׽hm8ms&"X!eV [U#Rc0<{mEPIh 7wd݁z.3Pr�bu�]� 0XFX&ޅMxJO&B)yt9;DD-Y|>SU j@* g^0i3(N%ʼ_N҄Z$ <3 #:Y s18u`tYHB\:!]x0 XG RU08(B"=qpQy_pM %1剭  ` Zqj3隸I4N-Rէwhj`�0YP+m�M> @zB\h8@VƔfNο [Z3ʩ5�BF0 !TyX_RAFwgZ% aR\o}$8J[Kv3u Hx~ 0izJRY'2&2XF|qds**S-߭(s(:d�;�@bjPG%/�YsF`�\:0$?BݐiqEnGϣ?�>Ḱq@^"$2F�˒z)_ C:!p±q6:  Y �x̐(=]%@ b3},jpFe0 �xt'(TfZ|K70S*7tDh/@<-(zz)9,sŻn:+)@�xtt^S,GԥZjN^샅 qv^%7&ze&L o�6А[Q&c#@bj�y}[LϣoLFj#W6rN<8(4`n3t;ZNDY-RNէK*ñ!ֺ+f9J˶092^G2FpF~q#2X_2)җ8B_ J(]c& %Tр LJ$0 >V �hzCP8@?�n׍F$H3J( D[BUR8TXHI0�3 D1/q)iw$FUѷ9H,�^xZ-;ܙ  8 OTN,H!ɭe q Ї�M@0E2$ J *v3,L|L\>AA, 1tpwjQsٳ!; 0! OPn7 |zab(F<fLt3j[e*bj@���)[4\`*`'"�@b`3C8ƈ^!w Tt#cRc ABX+%e2ȲϤ2 邈%�u�l`NUF_<-R-7/t[{h,F-;(0 ^ �D)sϩQ ܳO#҆Q/wDQXT9Y nh֋a  4uƗ.xE2-4R"v0Nq0��|odmB wyhy0pXA04CcTF/E Tc":Ao0,aH�FPr=peL tyhEٜn{v[T&>aRꦂ0 Ψ {t}C TO!b.YEMS{J<8kCʪܓ`Y+N2BT  ¨�{ h<Kk[}oBŴ|:,1]U N4F069I�a2dl'ȎKưe4SS/!@e4-`H@ &LJc{` &x"$*6Is#V0\\Lܜv>9lfL.+H9/3Q?1|4h7}5SWH2ޫB󝏾%/K3{ㄇ�jtaglib-1.9.1/tests/data/multiple-vc.flac������������������������������������������������������������0000664�0000000�0000000�00000011222�12225024651�0020124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������fLaC���"������ B�zAf鄚0 <w������������ARTIST=Artist 1������������ARTIST=Artist 2�,������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Y�k������Yl������Ye������eYb������)Yw������QYp������Z$Yy������cY~������YS������+9Y T������LY ]������Y Z������Y O������Y H������aYA������X YF������xY������gY������Y������Y������^vY������7Y�������-BY ������Y������Y#������\_Y$������*Y-������Y*������eY?������Y8������Y1������/kY6������Y ������FY!������i3Y"������Py#������XE������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/no-extension����������������������������������������������������������������0000664�0000000�0000000�00000000400�12225024651�0017401�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/no-tags.3g2�����������������������������������������������������������������0000664�0000000�0000000�00000205357�12225024651�0016737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������ftypkddi����kddi3g2a���$uuidmvmlԁ�'w�����5���<uuidenciԁ�'w����KDDI-KC�W11K����KC-RT19�KC-RT31����,uuidcpgdԁ�'w���������������������� moov���lmvhd����5쾿5�_�p��������������������������������������������@��������������������������������trak���\tkhd���5쾿5��������p���������������������������������������������@��������������$edts���elst��������p���������Tmdia��� mdhd����5쾿5��V"� ��������!hdlr��������soun��������������� minf���smhd�����������$dinf���dref���������� url �����stbl���[stsd����������Kmp4a���������������������V"�����'esds�������@����}���}����stts���������C�����Hstsc���������������������������������������������� ��������� ��������� ���������������������������������������������������������������������������������"���������#���������&���������'���������*���������+���������.���������/���������5���������6���������7�������� stsz����������C�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������stco�������7�� T��j�� ������"0��'��+w��,��1��6��;[��<��@t��D��I��N��T��Y$��]C��b��g��j��pE��u��z��|f�������������S��m��������z������������ý��ȿ����Ϊ����������`����R�����8mvex���mehd�����r��� trex����������������������mdat���free����mdat���wide����mdat��libfaac 1.24��d3,(@PlT @"g5/<3Yn]Ji#qztm6?xwi龅Ʃr Q<fGwt3sfv5? A1@ztD!Zz;3=7!ۖޗ0e<e=6L,!e3ߨp,*|/4n]9Ah О1MA R]J�߿}7K޾o�8HFP\6)u/Z�s*:tࣔ Lɞ)q37:>.z"AX*;!Q1Յ((xu9C AzFO6KF-T6Q|#g}V/99u}4~A 13ZzdmqN+ay mݠ�poM�D���o��pB6HXRdbqu?zAs}:roL'0F~8u˭F޺fr D_&~%~VJ{z"O >),53 0Ā߯SgǟmR^Udy'Hۡ䈾ˋ(Kc-ǔhYx)+J~7b{:Y JYUDAXWM�{N�<U��@�GF ,8" H( DA`$c}񺫗xMU떹ֵWK|W'ֽmyhgK/NO4/=9PR\9yw]dxJ^tk?whc"zw;{"̼~E\u(( 8^.x$"0x�&H`�"��T*�B @TL B,8 !0\Z[;uVe~}t~~.;1,9ǣӫCCoRE%:37l),6H <�^ NH n'hbEX_UF{108VW ѐiX ~ �p(�@��B( 0X(& aA0@T&IUq̓~jw9%pc_NI(4{o:ܾy$(OV=wҖ恭UС?P`tMճTi:\s߱*G(K!C=?KRJYbçCﯻ"@X&@����pB(0X0 `P& BPn)k徲1ϳ^-\NoΧY_\f]?77y{4dBs]Jxy7ZĿ $]qWԱ}T>x{z�Ƕܰ.xQ{@sۨ }(kT=.1LZQ-kW) uE$�@�a ��&��*�DW,8 p* PX(6A0E/?iqݯxqgR٥iy鿒% Gm}jW4t+@ ӟ " Ӈ@z\ H 9P8quB{UQU/d$!1X.jg|X8�L0D(g���`���JLF0Y)213SVm;i(&DM>.1`wC7:"Nf;vy=k~O.r5w+h �K5SqrSbB�ޠi=u*π]6[/R(\#6H9RH4 `Q8/ ՇdvX��-͖��XB�Z � T�LMi*]k Sokb1n)zߧ=XCُ~(xn4Bы=tr=<roV<sl֟qJ‡CB[=s{,ANAR"sIy)+5僊NR\N/%[%T ˕q�.N�jA���ը��pJL `H p.#B#0U]gY<K˽'6.w|x|~vohР{I ͮ>k,wc&P^O,|y-^q'#cBDX_GR ><=B +�#ʻ M�.��$p���L HL' @$ BApPP`L"#ߎ+Rz++cj's^߱.~Ka<\'GW-V O>׺; {P)L-c=q@Ƅ+>'U~\{jWz4"~p~q�(T��D���� �`H,P,$pH(`P0 B0UМSU7WzVdϝSoC-_$ ߷xQŗn|r‘tohgoןK|ڟku"KC: >aeapB4bhiCF�W�fAiV{�bE�@ ��"���Hl( @, A@\$ ƒ0\$b;g?|Wu\[Ԛ}w:&.{ִ ?]ϕWk~/?g͵IEj^ҽ<|~K'o7*ft! i\IZ=q vS <& �,�P�@��T��HL @T, @HL4 R^<ǝoWWƿ2og/z7yx# hI2"fPl>[cCj|q#~&ܰX2ݗ/idr7 4ey?w[PyurB$9 /@ @&p�@���8H$ AT( PT$ AA(PJ <g]~̮gw̼qvJN̖>w6SP=\?C>3;/02@]"D+*kɁLw~Щ oj7CU5[%=18� �a��� �L�H(% `H, @\, pP& D&C[^/on8<ޚ'k6.!F1i܇;gϛ#‡+ˆw ht4R<-4\rr6-!-ljFt`BKg ?S3-n;p^2$MO' 曤z�P�P��� �(�HWH&BA X0 `* X|'w3[|o7RO?^J,r9p;w>93i>_*ϡİauP|g=d ~x3 cNjl!% $k|oԀB2fTvB'ۥm]�hH.:)|@D@&� �0�" �@&H`Ba/Syu7hXN6収qٕ7u" UކP1"%F~]?gS/ڍ60^%yO.Kz%z`qRh,r]`"vz{%cZM>n=&I[:=/:ҾN=ԥ`b*`{<C�߼�X {t��)�TpH- 41t+ցZ`Ϊ1ƺ&Kj=kiK6H[S,Ҿd6v9Io=ӊT/QԧbsYF' a3q{Ww qܾ-t<}̃*ME9NW0E (k��/BR� � 2������8BPVbc's6A1 8)0_?&}C7/|hxUlF$~UEF\k!͉E&@bk>(zƝrm:@t .T`�X�k,� &���J,^+*RW!jp%K< /2yφѩ8{qnr-M(TIuMMa;﹛ Qny@�,a|N,y~fWPPQ{"��>}@� @P�T5\��}P/P��F���� U�N ,`Rhbuysq&8M=RTc;@ ojVT.ߚ</9U^_PAg{U{V&nuqٟpI=s@_dDҍUFQӫ\E(~,#Vz>$R9FU��� 65 �� s)@����F A@P, @P, pX$ Zvxu.gZIxs?Y}ʫƮH}XMYO~-}x/fRҹ(Č"*�&� �P�&���pL(8  PJ  XH& @P";S־׵|=-f G|G')4T{yU\]zL~wPx>xYz+ 8ko|]ƽy#Fh$׌_ rM^iwUA�,��,�&�@��(�\��pJ$ B(,$ ¢A0Pl$  Ux~kKZznU:ry.nfZOyyxJ<`rcm_jٌd0ӱݾ:`!lf)(c*%cpۆ`W;F *~3�@P��`�@@��JH&BP. PX00"xeם^3φ_̕k#s`@,%oWܭO@�JԒW"l": fu>(v9<MLTWV.)x暣-mA��@���+P �X�H$PP* Dp\$@P. BaE U7zfe^52=prPs/v~oknZ>);r/AmzaaGXX*)W럜ڭSxG gf~mK1b|B @&����� @�� �H$BA@TH&0. p\(koo8q_>2.Z?ӅCc[7܎<8.PkT^Q7uh7./gz!7]]Uh$b{k1I`M6<�\�,�`�����`J$ BPT$ H&@P* -}kW|=w^{:u^fk&[C.. o|. _͋؃⿽; ]#,KTqN{>J2 @w ~S^p*)ؖ ~/�j�"��H�@��pH$ !(H(QT. L.)y߫\۽s57_9I]~npql< ˷t&U/;:Ew'l JY۫{9΀Ҳn41!|U>`K΀7�� �@�@ �@ 8JW$ "(P,2 B( ZS|oֹo̯ s8I5'׊H=SAxqѲFmUD:O +uUnCY=nwyfL? l-s`WZ4b;7��&�*@�&�*��L��D�HnPR$MeD_N4n0VLT*/Fҿ:eRRDX'}῍+!}6tFxouvzT5qx�|I8A- |x^N?p[%v?椑 k|pʕ��Z�`�����X�F4*Xw3ik$Ii_~#�["kS%0եORL-̷- 6ȓaM|',ȽȺٺ~^uAD! ("b/-sٓ[~Ogĕ:#jp X4@6l���6F ������PB&0Q1Rk5788 ܳP+Wȫz #_YJz�9!5khR[ f.{?x ԉSi~Y{BohEOW�MUڝ3N/<otw^6r\'|aP\� @���ň���Xi�@�D0QBdk2:ZEG%�,;7۟^7[[9}) 7la/ZeSo|WM,F{NGR'-UQ_|/{Lϭy_w|8[Rίe tP##�sL��p ���5���Rj$ P, q TD H*(?jUu7ϞU/_ēM jusz*]ݹ?Iw>9tvfkՅs@Ljg,O^^ÿInիW! ዠ$k`Xx?`<p� P�@��� � �T�H$E AH* aL"A0__oUxn\&rC&NӚIGwa@l~.Γ^>[v?Hzc&h!#1C~ O_;%G: dP�(�`P�����H$D B0\$ A8H" BAEۺMwQonuw5^j&꣆l2+E9=-F߃Go#X&)sGb?n3<l y~y@~ڸLL.T�B @� @���L�* �FW$ ! ( DBPD$ ! Z{޳5{޹:5AOլ!ו(,29_NcOIͭվy<:|":X`sŢH7WGH�@%9 `� �� ��\��$*�D ,`T5|݌?Eg0u:mkK[iX[Kx$-^O9{b5t)Iwދvu?Qreς;xw9LR箕u.18>"bZvp.n. :S\T/0�(`�Au��<("dRx_P 0 J`G؅Nctl0זfd58e #@ሹz.3{(|ntOl!QEH!/!HT"$ȩ7(0)LP06qȀ,�pNK',T81lַ?ŋYwON5 i{,8Z557O{w'@P%uήq܎DFkoTDmXK qv_UvpqD�E D�� ��D����pP '(ԑWu]k$#@tqO^sNZ5M3YV5sjy_@zR&}ɡ7ۧvN˱w,nӬj=|`I=Ԋ*H_{Lr�B��@D�����@�Jh20_w(]{,yy_VR]qYp)1j _8H':Ul7lo�/ A eĘ/?kG.!5!*0<C ��1j�����D���DpN(6AT& @L"ׅqydeT%\ʚ];^oݲo~{_j"ӗE:T.x%;}]Q.ÿ.T53Q9|%@'9u܈ �p0� D��� �JH @PLAPL, b@P$!ixVs5yG.R>4~gP_/4z_Ƨ)RZW !Sx骶77aɯoI t(svI]%}9lX@lg, ����\����T��pN*  HL%  T( B ( XYk:{eqUS8ͯWOlJG|<<?\+ Z͆i=8Pyv^SfZkf[>2 �/.e!MH;ZN @ �X(��p��$��.PJ  PBBPP, Q z^ksk_9㊯ЅV~]ڻlNeyV!x:>e7=@Ctg_iQQU�Ƴ}3<Ē*-{C;SRzk]TޥB1 Q @�X�B�p�.�� ��FH BBPT,4 aP$ Pug{ԾKN9xoݎ65ȹx[<./o/زBQX.ʟ>wOTOmͤ>kJ@vw*]&;A%Z��$�� @��ˀH$ a@PnBa!X( B@Eo^q8*}je?y:iɶ<(|yCʕ=Pfnя]ByO9驡ء̙+^*՟"9!{>y/f��@.��( ��*� �JWj*@P, PT,3 Z9ճ[MSuU xY|_rq] duÒ*)3E1i߉ :C-?Nw6oeoFBy.]BTiRgMN㋚̬?{:�p�� P�X�JpTU㎵:Ǵ' >R5"*BR52nty(-fe>ziګcY 2@\0&<.}(É�wz0\:.f HSCH=ҧi"L$ 0�0���H��XT,#0.@T(E⒞\㙓zvyί*k/Qz ]~k%!oN~~!7hM/?>I"?{J ?!M~tira")IAK:`0�@� @�X�H��R( H" P( BA<UssZzu7[/ƗyUu {w~em}%1{baĚ3V4C> D͟<rF?zíGAĖ2?n$(^b$*j@`�H�L �@\�J(%  .A0HH' \~s޺sS5N<o|an@L GjLw]S{L;"?dtw\J MFu-St*]@@�@�&�p0���T(�8J(F P& a@X(2 Pӌ箷y/?Vn)S_Έ;AGwd[̝[Oط;V >.w7p9)�8$g{Al_ +}+׸v~9H!M%M� ��L�"���XP�8J( H(a T$$ 0X(%02otw;v-uq:]p9;Q4s.mYj]j!"RlenA|v}?QٸsFyKT3WI@iZ6�Vw@`����� &�NW(% PH( CPH, ba(H"U}yVKS1Ԟ} %ڼwa=- j?ROJ6q2ڇXyC#%}ܚ/ d&Jo=^|reքAu/J%qA)`��L�`���L�"�D,T*qƅk3q:l ǺRp#]^>M^t[EmahaU%W;]Tk*Y%!!*b75JR;^uFv0-QCHจ LBPm6kJii'hjpE~d@ �Z \�l�"@��L DNPEB�` H6pҒ Y=*kWۖмyb9BDQ)SH[7\`N)cu>&|u{di;;U1ڄDbi T B�6#3U@��lHB���l��� H 4,PBdkYZ=q?, lԝ-ps׷]u2T_M5m<WCqZ`7S�Osk'"ѡ,ѿRgz4O4_g/[QbI,+Ǹh9ϢWUNhz2"�(l`�\o�����H (,!RdcYVf@JP"o6Y$nlcY5Ra厫+)W}JG2l ek^k.oZvmg1yUsyv]dg2\<zlH3-i!0U0Թc09'H\&�r ��(����8P g*M ]b_׋%-%.CIƆ3M|aX-Mq6񷍼KgѕCTpE9j5LR6/mnuqzq8Wfs#$&b+bxjӣ0,X�& -)B��5 ���L�RH6 PHH BQ H& BaPYg +U&+۵d{n]%˼M񫾓 sv_B|)t`iu.]jCG8OJqЭ5Nw}*ܮQ~{M}7ԕ-{pj!P`P $���. �I@0�8Pj  P*"!0L$ QE[ b]O_}:6\{KXxUt8}Wvww0Ҫ/bѩ9n:N#OM$[B즂kp"R*T D$�*��&� ��"�pJ(% CPH( ATH A(D&c=LUuUĭ~˶SY:ZېiovecUgiYtr!^ߏd.R{<m !NJ]$:dDp#?&)$&QU+H@ `$��p�8DDB(P$ pH* 0[qz{W}lƴqZ_FCRr G>]VBts/-gǗɱy+mg{βZ4߫ 4V08� � `����H(% A@H("  P$ DaPH( a5knx槏ߋ\N'y7澝WK}e.޳z -'(qTF'wgV96Yx5G\U>%j0zK3� ��X�D��X��. �J$  Pj QHH bPS]\qʪu%ɪv pǻGl z;,>ib.<6JCٍxoM{̭ s9%IJu_@K>1L�� ���� ��X J(r a\( DB@D$!Da/dOn>ٝn|ܮ1i5.ct6s{osף�Uwo_t#^ZHS?G[}lMa4/;r$�$`�B@� ����H$ B@P&!"B#0^߳zg_m$}'7/B}zy[k_6_]@^ 6ÄS˄v.(qݠ2(f" 3QfP��@&����L���D�FWL A$# !1L$_:kN>x<q9+I?.]fqz0ݏþ尗w<<|4Eݪw<WA5)(RsX�$�.��$� �`� �8@.PDIjUu?v9 \W(QA4 Jfo}tS]y!G7hOjn~HP^DϘGbΤ &oӇZZ ӎ׃ !DLH�� @`8JE(KoЙ)m6NH)uR“kVW5l﹭~ynoQY\Pb QSUmtݯDɪjӽ֦hҧK)H?FD �7� P���@����J$ !(H  L* B&0Ϸy]wrI>?j93nqս {ӻݜ(ɢj28XMy8~{by hz;8_ ym6∈H4�"&�(�����F`� �H(5 A(H. PP" BAEr羉~^{wlԪR9;~ kyoWtƤ;u6}PqV*iq|eEXox.'d[mˁt��..���\��@��H$ PH* `X$ P$!Xssߍ5}_{"^_ưK3<:ȓAgB/E?kV(Z.:9Wq rCƸ)v }Bz>6n\<�� .`����T�pH(3 !(X PPD `N=s3~kuʃCׯ{j)Ucy9Q}z X$n=38jOƲj:9} N)|Tփÿw@?P"�� �D�@���J$ APP,$@P*!H"u5Yǎx}q*E_]}xH9 ~|NϭqWʟo2֯}Jk.㶛hפgAXa ޭ!&}u>ZSuE^[HJ � �����.� �D�8LWF !( B!(H""3*uCmnD]nZ$r>~-49uYx~kмZ|{m9yMP Z߅n&-L)CL4B eT. 6��P������ �J$*P4-S?,'E$q3"Zr"h.ܷPVܬ(9pp/xR/5)9SuLn?�\S�siGJ{&D!J� p����B$jM eku`sTj %k8k "Di߳h> 'I8v#عa-tn$h3;M5*Q[5xgC=ajPi櫺;;}S.[n.s6̓�=L�"s��08J )0TRȼǟYрĹnֲ5 MV݂5*$T~:yaLc^[8qc϶i9Ez~vUMպ ?_]LuZ Lrx8]$ ݹ<\A �(��� ��T@���t� 8P(XBhbUN9qMp?RkK}D| MqZC /5rٗ=Z5x[dMRC:%Bb/ŧNНCO(\{V3R7ǔ_YW^4cu5m=%4~/%aO;hXu������������T(F B0`(" A0P$ -f+>v^u%]T;|~ѾNyC47 W5rrct; `wXe=5-K| K[MGw{b�M ���(�@�T���0 �8F( aA(J q H* B L"Ǭ*dd֕%q,99l}>iݯ-1gJ*K~|5MnɇǟfYX=<hzY˛ikNdnM)_ YI PN@ �@*�5�"�� H( AX(&QH* Z羻UlN/*q/oʼ'|Ogr%2vYW)٠ǡC|65B>[xȮ*W=LV5h|_1:.LW/ J`*�P�T����D� FWh P`( P&*gZdUVW8M·i8}G^9__xn 6~JG|VzJ&vy8sU(O R٥;&A;D &�\��D�X���@.�X�FNYUj?ð4>ݘk[o }qm0Dl` ڙ9d΋:zR0jsXAjQ zǞu) G#ֻSʐ#D' ihhfd7y X|j65e $~6�X��^V�������pJM21*|qz�29bcWtUo.YSquF&4DlOGTTq eeSYxZ ߇K mXis/}QW%wآWIO7g.XuMP]奮v 8@ż*.�CV���jB�����pJ D,QT^oZή[31ng,я |{5MzvgբK*yti+t<$5bf_hϒ>Ӿr 킡,~ >+ x@b3T9H$dwpqL�R���k������J( (F `H* DA0ۭn_9ur'N?=f6tnϚ uoIG,]�KJWaEea̻bSSKN q[=xVQ<q ڑ!���X��`�H��&�HWL aA0L B@H0 @Fc98Y<kO Uԫɩw/'{*~WaKZ:?}/H5HQ_`78& -_?f Ǣ tv.X WoǢ ϐ X~ۀ���$��R���D-PV 'HXûhMj,1X:*%: �Q\Y7VU{³%gJeS+lڡ5J<ckkӪFWJ1=7[K w|jr`�D������iJ$  PD AXh @T$cs_<3띤oQ{5wI~޸f6s/G&js2*~w=ȾJ)?/!Ri)[Irc7P< [Ri%I%o\W]&-l�@@� ���$`��pJ(3 B@( A0T, -qu^gguFK~c{Fvo_XmsŚ vP oW3.?H K`;/'0y>IAǩŻ~)`Z<MDpi� �, `� ��� LL@( PT,  TH ZgG3z;Y3$|t99õGߋNzZ>lcR߾WpQqw(M_xZ I:g: ZL=_. pg׎ }8 6:Bq qsa " +� @� ���(�J( a X0@X. P(*{~xS8>׎ώ;nqs^&'u,ǿ|U}'B'=T}23" i_=blwi)(Fgy7}0%N#3<Ep"ntvrAM+#B� ��� ���J( A@L$ BP\, a X$k9ɚ+5׺kOGXtW7M%O3{$c۟SQ*͘jrj=HKGȘYBed�; ZkN9 S12ٖ 7  &6b���H�����D��pJ( @* AL B`E^y|[^J*j?Ū]p9<>d ( Vani-\=[> A2 7xNG]YSi N:`=o !!Q�2w`w)UiѤ?5J+@����(���J( `$& `P,1Z<VxүT.MioJ+䚛_>VQw. RS=}z|M�HП5t#W=*_5 ѓ ;]]EՒeru"Cܘ%`@�p ��� @�`FW( `, @Pl -qǷ|UL5ǫdrknvܷw}σ ٚp^eiF}y?,[Uԛit ^G&v#zP@4S'O}b*^R7YW)\`h p�P� ��0D(,ЩE:޸޸�4Ȉ@ai o.agX]*}<.=X}+jԺ텁5g>5ҡMFUX\Md t^Zu]7q_i[>؉y.e[3> E[��B 9d�����L���rL (- k*{�#CTԸ zw{b6:8 <Pw=Z9jSz.V{jqfNa(Ж؁>ԝMHfb)P2.{{Hә}\ (\,0eǬ@!AaH�F DH�X�P�B���pP( ( BQ . Uλ뛿/q&֪u<u˷{s6vj 6Itv%f~akL2,gi%gA͋N:d 0]q���`&��H��  X�pJ(&`& ‚`T, ¡0]沟~rT\W9jZ~8g^f}MQqoSBߧ;_?n_ZA^$&+Pvtp<Ss0> KA;vz" �" 0@��� �� �8B,T B`Pj BP,'  D& TTˬ雵E#W&4r}{4ImST8?[o¹+~*`Sy،>LIa7<F75J7'C[pU< $nf>K="X+5D�,@������Pl A0PL Ca $ 0L"U.sz8njU_h AZ&3q\Jt{ (Rugc+=][?ԟD6;i56gwױi]:}7{O:9in�`LD� �,� ��"� @� �D**`PL$ A@L" A\]~rssz_j No&|{PVlp5;s]u{;"!Z>l;+c6ބ3B$!:d;٦票_/b{~@��@��������Jh `(( Ap& B._2):zs3S/|,ָR49=(M:Fy(sqptφ%l3a _m,CMku𰭞ȲobxL^; h#57@`@@ �"`������D(Q0`* !AT(& C1W\ۻ<]V嬖9."~w$t9'B5./Ƃi9p=WpYUi{|)S{muhD7NdaQ6+l=j\aI����P\�� � �pF("BBHn 0P$ A:zoߦ_5 ,xE=~BԛC1Gm*ҍD_YumGn[V,D>A#J !j-$TMh��P����`� �FWL Bd(BQ "3˪~껻L+W>>>CϢ/=y^a&=.r}K?v]3!sAl䅫 ԤJ&|*Tjuٷus.F� &�& ܘ���&�8 (,\2R-ud"}b7.*3~^zSOCUx??~"].͚:d<tU > <ѧD"j#+_En-z4]n,Gјgfxh`|Jt@��w� ͛�&� HD,BhbEԹ5)ou<\K*&葪;܌.[~q:$Q?MǐyNGz4X7ߤ=G: F ,�ɺxsR궟{LY SQK+G'4 nsM87 F3 �&^s� �X\ ��'1B(PX( @`$ @(jz^^yȥw^k^¥q?;>'%UvPpsd9Q<>Fuy|l]Rn UA&B-IלZUsGzNƋplkIw �"@��X�X�LB$ PP 0H Ba8\}[zq<kYr5<2hxW|?<E8l;짍8?d ڵ^n͟^hku�R.oPSf<iMg. >~#uf{ =A @h�L��`� �*�B( bT( @(  P*X;Uonֿ%]p<\ ﷕&co ^Eɭ={ ߙ<~:T?/q-x5/pMv\9}|" ټT'qBγ �8\`�� Pb@��@W(&a@$ A0P~U^uY*˸NYgߺ?:QvSf;a#a 6gD}n߉<Aׂjba<̇ѨZF4ˉ|*>{Ө:. @��@�(����86FJU׷gUUCS'p?05Z4,4 kͫtTktVY.3<�|UJ蜫|SiL;H )SN"Z}2qgSj^7_cok7^kYPOX�jTl`]pP$E�1J$$ `T( a(2 ,p&^޷S&vݟbo?E�Ӈ=|(wofa8{KHuʹ΍Gםw^M~s۫:Kl&_7/<$?# <( :3,�+P��.�� �@p�D�HF"AP,$ BBnߏ髟]{2U.Mf58=?6u;?6-X|hE}<>U`egq9{ Lw7ʉt?^yvj)aɿ<2UTzO(W: dQ9Eo@@ �@�� �Z��FW$  aL"׶I^V[\{C6| ?-ɮ.?+[~=ԠykC#Zݫ? kFŪΨrj$!7밗CnF?*@6� ��(,��*���FFPQ 5"r؈8OL,TUpShm{D$0"Epű=1Η62Q^4-tz퉂A'$rk~ .,!:֮0wp?Al9C){(u?~;*@u7:@�o.����T+!P,8 B,$ 0P, AE-yn\ɾƷuWުkN+p6GK>w_w]Õi<k%_v _xT;tuÃ*1e{e]!wޫ~] EI!&uȖj,c!.gB1a� $�D�� ��F( `jA0J$B09rZe:]\ˁǫw~u|iMGo+.kyt^jn�CHa^6#[nb.90OZaǜAg;ZΆ7/w@/9C"t "-0`�H� �����NW,T`H a ,X5[tboYi.y&G/;WU};xBkJ ]FdzHwT9[~S/Qm $]7Uմ{69W#9!X^ L�`@��� �pD&0X j|yk 0;_7eU]LBuSV3t4A5%VX<?xQV_`ՕGЄ"@[=:ցSY4-<AEa$!XT80l/=M>97y3 txK]쏾#dy� f#9���6"���D,��8N,T`T( AP$ *g=_wW³ZLvk&8,v%Ҿg~'_&X t/PS�>jܯ9rޞ� 6标t.\H8#&Mw`oe}[\sW}'==wzg8ofyDȄX�X��B��\����D&" ဠX$ X. @Tb|׷vZJқ'%9_.:L@Ѫ<Ҫ_? F_5�7k~Ͻ̾=ʠ~e{uE9P/D|CSH~s1;M-YqFcgɚZIIX:l�@��L��*��J& @P,$ PJ PP"îe\o.LUy}-|8KB?&>,}3B؍:b=HwVSƠ9s*zÔ"\ki%tst(}z# Jl.0QK�H*����@ ��RW(8 @( B#~YMֲd/Iw:o'5G_r۫~fX(?}i&38z*꣺K ˻.:ĴK,^ĿxAȐs UZ&r�ŀ� (���H &L*_t> ˧m"t2h5GR>\)V M +|G)}g9$ml&A1~b^Ift$TRr`"S$pJ<JRLʈ5,X-ǒnB9<Ƣ=Qwwsl  8Z�p,��|�@��@� GL,$ƒ`X`XH' #0.\dfJjZk^ZB.؇u,R,Yn?h%.,#0r}U�]ꠧ;:J vs6{l}o3Y'YeNk._=d blg@[��&�`�L�����L,d A8`H A0T. B@E|feEIT_}Y壷!s?Lg{V<~e/G-Ļ�R ).Ȋ 88 8$? a 7Y-I;^b8 퐒@��(������T�8HLT ဠn@X$$ ,g|{wYs5WR*k.keݎÎ_ʟڎWNd7/>J}t�?̢/:vIif Ga-97;gR<ʅ _eE9ZFjUW`��� ��*T�8DLT`,PP,,~WLu[3dq֐r>v?]Wvr?_| 6׿k2J.W~wWз}D~\ѫ/0W֝lo-T&N1*X| A8���@`� ��J& `X( AA@X( ! ׿v煮MfurKhv}wos.onLJ,2ķ7^ /B IRmY?6=A*?c}VH]Y(%֖w~ ���� �`���J* `0 `H B0H"Ǎz]Ĩ߮㛫ky7U| ^6;Ϻ[Bąf%IW; zxv�>>r庯4Tga%vHIDMƹh$m8ɍAc(;N `Vv�\@��� ��\�FL B X0 APL3BAsw_⯞VUwz|x)G3{ݗ砏t:H=}T-$rUZ,`.?KҾč|c�Xgqܯrw:p]G}s)zn@вTp�\�`�T��\�@�@�FJ`XP$ Bp(% @EK2ٹn<uʻUk8p;M-)8\ח>GY>_%LbKùsYv#;E׺9jy ߣ7.7z [%5v?ͱ*tA 0Iԓ>[MP�L��&�.����1�H( PX0 a X0  [d+R]~rxGMZ96h `{P+DϺz7TNzSS#wyz˰ͪBs#/-q�Ac5N@OB vpmw"3NI: t��X"P��\� �pJW(AX("`(6 A@Eێ7xeIULy^8_' Oϟ|q0(y&>dGup5 LuK,%Ety:3+?M eL !8#*>;6_X`]1|<PZvVP@CT&�P�� � �L lԙC]q|8N fnuzsz-"iC\y%m] YB3C?o(u[U.2UDZL~CBMRTuH e&m3|vr=sZD;?~G3' �% ��̀����R.`H B@P*$*Zg:2n\lp<䟙<#з>ug@BZ'Oo =}}O0k:*sr'])q Rҽg P6nKh)Wݬd-p�Ȁ��P%$�,��L,' @X( q0PN B-gmnqj8SI8J#O ^oKAϮ/}%_oklcĺO\-{)h0`IY}S_8 ;cB6^3Q9]` !� � 0�&���J, `. @X( `"{jS/Rj{*49/~=i.K~?-C2uq~[m E$aT?:#kRu]Bem˥;4(q \#5ͯ?h.ÁRz‹MLu��X�������H(pT, aT,)Fa;굾*enf&4w*T9{?z9=FDzq?|Y-=c$%κO8xE�^?#N_8p#U2Oː_/$K7(�\� `D����@�8HL `P* a(P, @(1knT;2Z՚.uQ%Ge?;g?u>~!=ڸ8~GC:8=>E>(bjeb^ew#AZrQпs^9-'suV"GT!�@�(�*�&$�����8JWJ1€P, `*_:ޓ)rdZEΧ>IY~ΦܨI G6|\}h4Fz>7WIl $Iz"e_ 棇_6Jp/:6XQnH\rdjLOШ+�% @��€��.��P�@*0Y20"7|=W['>}=zucJTBxfIKKSlQJa/LyCoͶ(ƹC$ՅWLCšk {0Ez19@X[c.ͼözƅq. h D#" � X��� `k�JH `* b!$ VoD2Iͭ#8'_oողaw:kɼy1I�=}GM4g> ѐ/8'q?_7_ۚs! ?fݙ45)}d 7\a�Na $ �@����EPD$ Be X( B@P$=|R \2uǷ=ko]g|rWDײuK0 1�Ӎؾmirr#;%|nx&C Iif52вd-$sY?߅��(�P0� ��( H(& ),$* Au5TѻArO>T;n_LzWFj}x%dԻ OZF5\c Hfݡ$w?w'XW-sݰ1e1]\MŸߢ 1B@�.�@�,��*���H$  PD9 APT"k[ըELFk]eg$o,9??r ͞RW_"<n;JҚht6K㖇iя0X7ChWfB/h~7:iz{ Lz?lФMԌDr�)0` �K���@�HW( D0,4 EO?tuj_8Tj޹Yg\mgPrd[>upRTmI"Iœjf9K/^G7{\qqm c0C㥨9N[;Xbš1Π���(�`����@+D&F&U\dbː< x`.4$+E'n(0 zpF1`^L!F=Ca:(*JCQs[k 'M2'~xpQuQf^�BjCDZ:`^yC[׶Ycwe.P~���m.���P(9��J( AH(&2`X( EN>SX˙V_SU4;\.߮r_#YTٿ�=DGǃyKZ{7 [*/;pm B*5'!J땏aZskǨY6/>Z2V_ȴ, \U��.���.����J$ `(&$`h a5[Y^wʓrK~|7Rj;#[\9o0_Yv`'./SJ9I2Sev<[pgoo*phÈ4QW M5kST5^F�5<Zf~FL~#�%T @ ��*��(`�� � D* A0P0@\( T[ͩn"SۏYrw3Of#} ̫j5J$ ? SH|kFt%r^UjMK@EW!~Iε̆3Լ VVߊhtk|n IEG�� ��*�� �"�FW$ A, PP B@$ZwN%NzuΧ>qY2_uhv|<;[o'o`3O0%²p׌Bk'I(j^ȉHtz Q)"k:Dz^b JM!I|!�P�Ap� �&@��8H&.^ N:`,iSu$ V(Wܚ3=Ad Lu0<SEQ \sh롢+:7dƌCT2 ~yH1`t@'o^\7=::A[l|T ',7ײR�E��a�����pDMKޥϯXj `Zr4.evGX&5 b+1d;GŪ\%*fq>Qlk9nbB% rSxIp#d5Et`CEgD/i9f٘pH��.�@P\IW.$ ~$YX\KN0㚖zj1ЩsqMV<sG,BLVs:舘PHDK׌ 3%P/4�a8 UԶiYM|͛6F_Pș�O��4Ȁ��!"��� N- \3\Ozڵ뾦.fWjeOhGahNV?,z<rUn"{5im\uMWP=$/�ϭ_mmfD R7P3RMX=H0¢j^nJģ'6M�!H�jh D��`��R( @* !8T( @Hbd|UNzK9/5ZB!ӯ}8}~۫$ k /4<bXnd_s֩Z^j_/S^#݋3"f=��@�X* ��X��� L( aXH& ‚ Lc4sK׵9V\[Cq~o~?,]]H\<vP;k& ۻ TWDY[`tg޹VnЕF?iJ 1`X � � �\���..�L,' Q X( ¡ TH  E\]Z穛Wi~}%ImM~e-Zg:ͣEz7-7Sw]ESpR;J{ڝSlR >X{HÚ :lwN{KsT@�T���.��@�X�JJ$BA1(& BBPH~&Z*M/9Z׷_ZG_:u}㱩+g.5z'oop2[㬺N7gl16Ӛ"hv>/ ǘ50(x@ <5 C@L0@@�@�p�.�JN&`X. @H( Ba=sqw5Zוkv:)\V#mV`GMqc;vKj[Mwvzx-||Gt%cw:>v]=N+<q&:~ (Oj {Fkb*�p�T�D���$�\�TWL$ @, pH*BaEfsU.S}w竗.Ԭoz8P,)աWA(Bg6;rz8Γo#pWc%b%eN"<0�LP��D��$� �P�8N-\<v/]EOMGJ"7`PvKX73%^z,=},5# !5ʐ$-H>xgx֨J~c{ -nh8?x2配p;&Zs1V^/dAV_} 0� ���p�P�pJL4@Xp Q T." #0\MV㛽M~?Y#NcϟT~ Flz>N|Q|CPOzh*)z)<Z}8"KMNc&^ AwDeнLKml!@ʀ\�@� ����JL B0\$ p,QTFa7z;_*.?r]G{k9y7?q?a[%~=d.Ed #ݟ~8zJ۹wJ |hko,aQ Bh[va *��,"�� ��.�P�JH B`P `P* HB2sRN|kzgCdzÇ|~(CHb]>5]OlI޾o׊/m46q"!GP\11y_]jUe ȭh P����@��PW( `X.AP$ ,q}ޭ5ujq6 -7oV5:AF®}RHU :Jnn\C'vO>Z#?sĎ'A:N(QQ2(nT/��f�"�(@�@�`��B+((TK} SCmLtFכ %ӼR A9Dҩ&EFZ&)'a.H"D=]lOH[HGjaĄj//VZFҭkc@F+t#4L#Iv0zLGtQE ���N`^�� s�\�F(&"ph' B@H"[Uy5W2Juq?nԾjnCmh[@%NW'rl[NG:Z7HN(?C}W fm.hU2gl΢Ywv٭zkܪ {Un*DʋHn ��*�.��*�8J$ AP,% PL$AB\~uny{U)'Vrx>:y'?~)ۿCkF⟲0CU}T0sSQӆ1OEn2?B77cDV^7jq6&El,U’M �0@���� ��H( XP a, aPHHU_o7t8J~1(>ryp4NiDi!of &O,cj!C|/#Jn"Njo qE`׌)h;i 7{ L{-LQ2t�@�*��� ��H,‚a@Pl `*!A733k$ܒqN|G>|Ρ6sL D;E~Ch;yvG՝5_j XxZ)�ϙ,uY-,ֶbE|‭f���H�,T�� � �LLUP*‚ T(" ZY2(j.R:NKuۣ~u59ԁMjxzy,M~r%xՐx>l7?@*U!<@2VD �,���$ ���F@�!`FWL4+B0,$! A:UƫƵ"U䚑:{O>+^[ﵢRv׶^gjV K~uN?|kOJx+}oʰ4;yt cG$6D^WqI!0�*�����\�*�p@021SYs^WHI";>/WaW{/]똲az@%qMxՆ@KXB(dW$O^=J[ {)[A;ٓz.RLQ58ck@~R[b&V>h7s�Hx�h � �����"8R,D ဠH& a . APT"=ⳎWZ%ξԑk}ٻv?jnM$w;W:CȜ]/s!q.%PTDTfsf+eC7 B1y}XQ�&��.@� �H� ��J,c pX* Q $ X<Tq^ZK|"jn?u\:?@xR/3t9/7E] 4֌k%WS_<bb.~L0oc+A-j/yj#cJ^Q-L�P@�,���.�� J&" C00D`9ƫϫK72II:٣˄]MWV79f/@ىKv;(}ZdA.Z=,V vW\- Ҫe  zS)s|D]X&۸7�.�(� D� ��"�p�pD("`P,pP$ `T">=)WΫx<^6>mwbKCEz"/y>M"a|{!#* SqJn=fb ȌWNG9s9rJCiRuZz`@� �T����T�HL ¡APF$ a X*P"ymWzU=o\Wipr;7LG-q߻K)5;6sY>bNUvϔ>2yLW {a0nBpO}%Q/ξ�] }@ �!0��� �*��@@�pJW$ `XH ¡A8P,$#b7»󕗾'N?erw.Vݿ'vwFߎo<oɈ}}uzא5>nUJu`f.kt7?qU@udԚhYc P �X�T��P� B60XrDKcw?nojf/0 R!i1я ׏F|}%n4b\4KcJ8KՅ-R%<cFckudٜcOAmI *QZPP6D\�f��e���v����8D( P\0 A,PE}RuRw/}U]Ln?Qr4= ko;>ѓ_yw^޶rm[t 7(-oF[q>> 0!˸U%VPv+/ N'3VMt3ʑX)YSV�.��"�@��T��H �BW( aA`(APd B-kyRofu^~*Dյ)'wN~B�V|?/O/o&u!\k]}qzu3٢s5)cYKxԟǖ2ol‽T#Mn@g� �TP.����P`�8@PXRdaWZo^a?/vavZÖ}$GE-)1YG+ ܨE_ۮxdMp(lzGmB?s4t"}Vp?tʯWКt_>cۉah'V*Ĥ�"C@ ��028T(Aa!X( `P$ EMnx;Ƕoxԫ3j#ߍsE `_wlO37/`ܬM<n)@MttJVOk_iޢHsuѾUΒ| -: _:��@��r@`�TX�pJ(6 @ . DPH( En\uYu1Jn<ux?)ĵLbBbv{kU+芎!CbY͖gխC'wVAo،d2k$I�����(��T�@� �F(pPJ@P, PL"׷׫y^MLLuur^7 Ά;T_ _?}"hmsw _˽wH4-%`# 7Ո :$xRœs" @� �� �D�.JLD pPl A0P*) XuNnfqUjyV-tYt\e 8^iwW-+ժeNwW+k(tt]B;ѻ֠DpDzx=BQȠ.<`p��P��T�*�&�8J* a `*`H(% aEKYRk$*)牕;_~*ͻS֏$/HKy ~:-*U̎~y+?+f 2rKD;;DmrV׿+!:^n,JpkB p��L�X(�"�� � JL B0X0 a X(& A@yvTʶqA-[; :GiM z+^uӿ?._w[_Dߜz:0/5ۙ]gqaO\-”3>,+f[a" � ��*� �� �\�8L()a@T0`XHB @E|] jw}骮'q^v[_?ge+RS*woKWclVWcӰEv'G suid pNnTTz-Ǝ2FsP �,�p�\�@���P�JL `T(s  P*\|N5f'ڪW_Mǵ] m>>kh5qYH:φua;;ѩgZ^#u' Y'~vxVbџħB־"&���*����� �JLd0,)B50*dSԫj.jk-$XyFv۵�_QƮg껳$O?%.9<iIP! \|gi|W!-JLckI8 @ʱQ(��`@���H@NW(& `* @PFIZnW[x Rd?{Q弋zG>W:ÛA'ȧH= l?")561SW@*{ɽWOBcoZ#!h @ � ��P����.�pP (,ܩ"55ֽt|W~QNrz̳LA~Ʊ@:~aEJ2o.s�ʍ#�3Vߍ6FJȭXKߛ%n mHqo+D8⯢40@L˙0M�}���@���>���O�8L(-21j^N tY('Y?75<vo<7M4@'5uL N< Hv}U-O� R>2c`!Y cWsYY+fv<`vNtlCܪ-L+@"� Z��� U��������J&0P p, !1 ^k4w$k&q2UqF&Ǘrd0G}k3y< %wp�l}rN=VW7)4ScW3wKrqPQ(�(�� ����� �FLaAP* P`* `ϖqܒe+]*U^7=>a^uo8Na=_2X4F>%lڲ<D!MZLd2Kj^Buˀa�����D`J* A8P, B`\(^nN7y㎿Lbw'^x'Tj0_NH? v>K;6M7van hlMeg׉ڶwHFu5&'?rC@I�&0p�� 8H** L(&APT$1 X5^JfZy~%ڦbjo?мV@oվM+ o a&tdGEyrAo9Ya >(JԬ:<:E΂TjJ������H�HL$ B(PN AT$3!׿k9MŅirI49'UEO{Ki@*u\Jm54At"9Toɹr+bU*x|aoVSZ~ZjlBgqw鸡Ѭzr_ @@H�H�"��,��X�`H, AH* C@ "־sk)5Ԃ8hF>}yoi¸+$~5˹/.;pDO]<Y܅e#vKX^rZ z4V0mJ�L�� u@@� H& @P,CE9іDAw=er~o~:qwC7X4'Mot×k17o܉Ea/t7ŪʬWUq~B:Lw_&&)EO"͝%L[0�H��U����@�\ FW*2 a Xh% a@(!0jEL"Kc|؛)>I Jzq\]q^郮/{(pPޙ݌ \W Hc NmYBk t19q&oki ``� � �X��� �J&0TI_+o}Bcތ�Ȱl\0Be$ܚ(x:)IGO+'Fxܣ95{dhM˓|kĠ 9\VV{l;ܷ]7} ki_f_Fyh�,h�� @�!" JD,&a8}; er{ODyY/u^ꚪU IOG~ qjze\hHo9@J%M4'Mߛ\ZײZGAѲ A F���$��`��hJ( aA(P* A\, QP$k̽s=p9}˩WMoWwH'G7.8p}?DK :Ok76F6_]K.TzatΣޝ豇&``@hk.BҴ*�"�T� �(�`@@�8JH& A@PnPP,! ZfLVzkU%8X4984i\ \ja5'(�e';;7칋t9w>"'IsF"xҵt&/詐Ks^o2+@8B@`��� ����@J* A0P`J ~׬9ƒIӧ|{ Ew7{nhVmn܎G#"U``y}${f8Iлɼ-j ~u )a8�4S"4@(� �� �p @H(& B`( @Pl AE|s j$TXy{`ֻV6✏_9 m}~gH惊m%3/<t }iVٜ 9)G~(n'M 8|Ջ:βۜ�`�����X��HWL @P0 ( A3uN;xTqZY&~7Z|o2KKu wۮ-sPE﾿>ʖ;l~ѝpkz۾N*;~;6pm5-L{,8.AQ0" �P ��*�H&h 84} 4 g-2ٓ>7e] Pn SiYHjdox-Np~^)[zhLȯ ܼo#rkQ^y5\6so35һhľC&TPH� sj �����;��&�DL( BAX0 @T( B@D&kzyۙ9VMe]>KhrxWC/}zx,jmNq; 79>~ >{g~>IR}+[S })1|6{->/5Ң.DbLp��P��(���8NW, a(XH2 H&ͥ<"JK*k'n.\mJ{or'7,u?gz}qxY}\.,BO!zA�5}q{~S-z/Dc$STN�*�p�@�H���N -TT!N*UUswX<vS=ss?> j*!YO{j8.Բ xMt2| `". R + #љ h%MF{i^Qj@YR$K盫t} �< ��� ������Le$LE5+&ݔ⑹+TrF$�zs෱WQ xRׂ t^|?.(-Pg½@r*%yKg%G3 @7Ⱦڝ*1 � ��6��� DN`���L(*!a T,$ HB5XYuZL9-Hī7rrzzͳVӟIrOퟺU~Nz+^%|)}#ӳʿ!{^=S--<}'}"^%l$ 60S4g e�@������J( @X(6aTH2 \dֲR]Quc;W/8?%[R|lAuڕю}kw΄T|8<|:h1T|d8CMSm)[e  �*�����B�`J(BA0* A`XH @T$s]~-.rj?ZO)௃D_}zڃN>'촶1nݑ YOrZ.>7{]E{gwt$a��*�aP@���@��8J$ @Pl p,"A7J_|4RUҪ49>?{xNOo Ah[.תm|7*t1ټ]0';ݻZ&ؙ)$&  P"�@�T��.�pH(' PL* PX(B BAʍw2 w<7W%WDjlN<=zWѠ7ӛv3O9=+/'<26t˟F }j{6'ϩ HI.?0� P@�����J(6 bXH6 Hj T헾z_UIyJ$'ݺ57 .:t#ؼS/ۂ(Mo: +su3 y{:=_CEeEsA7;EHFi[{Qpp� ��@���LJ, aC0P* P"3]wK-YV^~t}Tݰ=Ӆu~_/|qnkG#e?;{}UJ%WxJg!WuPw;o"M8j0j=%p bzǸ Q�`3�T��P� � ��8J( a XH& `X(  H( X抺s%]\o\i"䫩w{yW!פÈ a i|b%B%(sK[Emw>Ptp65w=7ٍ.JD)3F#r�� ��l�.�LW(@L$`(  w;]KQvu0UI}u_NCWi>߆s-M eߎMu0Hfd޶q @=vE?`o2"u&j]KAӑ?W@.���\�� @hLTf.Z_]1f]iOzky%]LotI}^|ö6ӺZwكR W=afW7C E[�3ts).|iҮ7;zsi(� ��F`\�� z�����H$ `X0 a@T,A@Ԕ]qTOn?Ӫ76iO;#~%^xĶb?nȤ9A�>vev?wIHx3~W>:K^I{\.be h,� �P@�D�@���D�pP(& 0 9C3u4/ZsgIW_eXOxqCv"Z&" u1?b`}Joh'gm wo}eSh #5G:Vz7GM ~u |@�,�(�����uŀ�F( 0Pl( A0Pd ,zVy%$tSo9<o/}^f߿)&KlށoqN%j<QQUr.v,wڧzz_'Hd;yihUK; "cE:pTOi� �@ &�@���8HL4 @T, `P*c\7LZV]U˷TIsoҏמO;+'Uu=]Ӄմptg T:|ϡz`>? o;5@MtYT~1*3y _&H{�@�X��H��H\�H(P,T ET"2" kԒqٗ/nu_<$C^VZH#$MmoImUF:Ro:aܵ72|7U0#}D K@LoSxr ��" ��`�*�(�JL( AT( B (%[s.TSy<TҬv<6|۟H~}O/>@/ےIcoK.];Cc:H!DSq5sQ"H//WgBl8b*qkut P�� D�� �.���LL B0PL! C7Yy&eJV8/_nN}5m=߲?ſxZ"/G/e_f>N3m̓7<dIx%ԃbNc-'_kB%ƑR�&�,�@���\��8J, @LD! "|x73*/MO?n5;l]|�]JG8 -mo6 G~ =_g2&u/z|;3=7."Z{BZ=]fO5F(YW'Ȭ/\� ���,����� �XW, @PJ1 AE>u7zȽY B᪗|K?m2t}BOMK]>5U-֩;wќN{ƪߗ}ʨ> ȡ�GF%0e->oGhW -ϔ"D�0 �.�L�*��*�8P(M iQyk] Jr-.A(WF)f+/,zjhEnD@7c);ϑew$!KυZg�{W .^3G%rC 'p8paحF'CV-D D@��u� �.5�.� HLDB0T( @T0 AA _;}m*wySoZ_wSBھ'aOE{gá?Mf;Hzʜ\wP#tv[9ߐZ)|q` `Oy7fOݔE^h뚐Ԍ` �l-�T���@��J,$ @X( AX(% BAH"{S2U[%"^}~*Vq~Q~QcN@S;8M꿀=5-{K2AƳB~ЄL՜gҲm'٫Z͞kFX##RAPH@�@����T0�J&)`( P(BEFֽ޶RK{}\.Ҿ:]COvߡuxaj֜g_fCEf<>>AD`d_#UBK%jX+jWGǶZE5L2Fkh=�Ȁ�����J(*aX(& Q L. -z/ M"/+U5}{ RAɰuާ˟x?O?_ӏt.݅w_fϥp#;]&Qώ'=D79wDWl&w4;%ϕLbsI5d4,~  ��(p���@pJWL3 @P,3 P(".̺Le{FCKsӏeF3|k?2Rw}k1jo#_,5$oPa/\kĐgg(C*ETvHlܛG:5 4(ޖc(,<� *��$�\�� �J(,21j^ۋzO*=K]cJq_z[HYR zD9Z)6{ gի]BB>Ԏ�#�HuPAQy]]P%;+*7V.d5떓pӬC;Fk@8 �+  ��+@��jP���pT,c`T(& (# X<1k7jKz\K?^IϞ~t SqVG/3(NOp4Wڽ ]яn ebfB׏UxqWEֵa[ٿIHםSr(iY��e��&�.L�`�P���pH,$ @n PH* ¡A(L"I:ܣwl\ǟt:{ y oQuߡq3szԩ?%^<md8u*ȟWWw k\v(jjv4 wJL&w� ��@�p�R`J,D PH, `TH Z ԱU_w&kοz^AcsODBݵ>#k?@F~Z]7U!BGx~V%c,PZVȿ7l-{w#`i�%0�* ���\��@J,H `T(7 ‚ X$ վ<5"|JJVo ~Kh8.yAE5\aӀ^&Eń*ߤ靹tg`[ZϫMnR8P��H�@��(��.�*��8J,e @\(" AB(L$1!PT̽Y(T:y~.rsMktzB8>b1s>i);$ml 'x-xnwQ̃\rQ&u'JfW;&eLP<@%��@�B��,��L, pX(`P,A@EtKJ]e&jeC?O7ukE;/=b[JB[huS@zKEڝ aИߧ8cE<&z6=Xyp{^1トђejߡ [.mryiqPsD�� \����"@H( @,4 `X(rVs^&^]^Tip9?9~u=~N}՞A|-MLz/OWE\ڐ Az.p[?9'yH'.ъʺFn\ V0P|@��@�*�p@0�H,4 A0* `X*A=LqT󗺙kܼT˥ߟ?QcU7y·+ӧ{r>^ ;=gOWn$o#<�x͠_2p7ʢ ߩq&{ \!*@-- !� ��P ����0�8J,d @P4 An|nkRRKyc9uM[tt[}Y`#lSV.X%GBCp(wvFFsw:ߧ*E-uw,LRxïy7V E` �� � �`����J,H @PL AP׭~x<$*&o7ԯKdߟ_sR?SMQK%$ +f[< ͣogj.WY/n:l6M͋0L,w�D�`�(�p�J, a!T,JAH"ϟZngU]dk+Ƿ"%+z_n< kÁ o79/z$c{0nbm! ݂)ɘɾu-m=5g@ŧ|fZf`Q�H�� �@p�`�(�pLW, PH6 QPBljwzLdW e_DYk'~4~i՟"֎|M?7z u{e{/ZR0rOO߷XK=%FQ PknM =oҧxehċz�AP����@b@�T ��L0XdHĔzk�emI-9 Aj?W|gtbeWe=h+8wx,3X{uyQVԢjz@TDgZOvPPBႲf/=#׎W<1`PaN;ތ um XP-";d0�A9���羀���z��D��^R,A0P, APT(&  HBǻx pSTZM,~ߪ|uԿetOA_ס+3}{czx]񑝊`sp|aRL둠7EJ<~6++r1>B)G0I6����@��X�@��pH&@l `h AEO5lj*/d"Vjh,}C'sEB_([?_kw?̸O➏@A  ;k܄A6O)7~|aqO'k6yz5nX!I(6^| � ����.�P�8D,G †b (& Q L(V龳[ޗSTKj8 ʥٛW4m}}v'eh~]+dۯ}'%ҼkTf>`�ξ/ gֵ׍!P>W<Y[R\ktԊ<Xtp0�`���L�D�pJ,D!@P,D A`(! T|ڳ&Uʺ񺸕=*H;W]"o|ǏsjCzd .>][</K3ɽgd:";T(/vƵV^}y!|i< l-B@� �D�����P�HJ,7 @P, C0PD X3ޓw*.R[QVrӲ}mj}V%tOg4i-폾8t}~~:o|.%Ab K%DlUskaHn2xiƒ[k#jh^���@�����X��D�H&PЌ% ‚PP X뿏Rb*)RMN<nI,u_{rދS$X:+wџ?,v9jv=]0;a`xpIO2St};aJ+#m1n]pǞp뒖'hSE,(@b@��p H&!@p  HBǫsX2U֩5/]Ga5tSi[<-ru:5:1v(%vqż}~Tp9 >ž9W隹W|yVJfc7S h1/@"������P�@�J&*aa ب `*kN*$RUqTZ'noqwO:ѿ Ǖ~7wOWĊ-DqrϯoAiGĚX{dH v7RD6Ƶ/lP- b` � �X�H�\�J,( aPP, B`Pl8*{沦k]‹UI(,r[ҿ$ ]FN<'FLEP豒ՇsQD릀Oc~}!~{c` Z|N^CV!'}4|nt^JY뤺X+% L*��PZ`��@��J,( @( `H aA&P\o|MɐWyQӏ.eKG7 >h�O'C~Iѧ_cP7z?G~ߺ�3HӋewse -~nQ>_nt|-m2Uv \���b���� `J& `P, `X(5 U8Zqۍ*[5,rLhsd[?fqҚ5p/wYӷ!c쾰 WdLO>5*m%tDځ ~) iZdN><mp>+@���$` �$��� �pH&* `H(Ba>[}R)tk3Y/_X<M&~:Nxw{uTܟAT<] ;co]jzNgyN# Ml\9ǖL𡈽+F5WT:hfWqRCԦG.TZT,����� ��@J&@P,d @X(2 a=f^fPv u7}Eh[tW´kj#CW}ɽ[iH9m�kw;Zwx>y4pr_f{qK PY~W *7T/�v�.�0���$���pL,T ,% P$~:qܺ^$UY5<J1>%:W*i*\wJ%:{f{J8etMw)zUϡ̉Iެw&jץH7qIw ͍WY-Q}qHL�\�D� ��&��F( @P,% Q0P,% !BaE/Sȩ"J=ʪVCGgi\II<'⾭jo8[î�?Xܾٙ(6[;]6Vr_ñ;#4`܎Z#/vf1ش/4Em+tUM/ZP٩PJ3�`P\���P��PLT P,AA0PD![UMomy2ZB矯#5>>>Kܟt|_҃5eQyp xY _Չ1d$>CsȏyȀH )<mĝ#Xn�@�L �H���,�L,TÀ,D @Pd 73(4?5I,rU{x]'g7rCMVh &YzCtY6b4]g,vBڞQMf h c2=@Lay]JrHy$l7E%NVG!P06-AM�*�@  ����NP&PB#).Qm6U{'㉡quvEJ^lƪ&K?;}99=c ]C^hefcBc�<L5u\h_$ʟ -:7GzBU4l]`s�.�*��P��D��pF&1A0P;A@L"<Ҳ!-Yi%UӇI8'囫ûF]\Fy |߬$п&gNcF_Iϗw)}?i>fB){pFɔ-]đw}e;oH.T@�� ��H�L��J,( BBa 1C@Eg&]K⥸~@I+[qt>;eM会!q{BQ݃z|[!H{iPEkPֆ(҆EÓ \jNj[)2LU��� ��P��&8T,t @Pl!rμ]uS#YRҪH⽾?uC컧׫vw[HzM(._9_@5K9˿c7QIm R3+2]mI󄮱t"CYot䈾_  @� �*�B@R,$ PXJ pPj ! L"qjS[. V]|6u79y1g�R>Qz`kc\myW6!v$ n%fVn \o9`7ǁh<L+'�R �`0@$��&� 0L,8 APJ H(%)w[^\xdLTZnM~F:piFc43n_?:$ p;)0ހ š9: />7%.MM^uۂ*� ������J,(  @JAAE~=}Wkq-S{Ԙ>v|<_wi:xn[ ^V~'Q_l[j_cPP3J [wj_S~vA|ۯ@D,�#P*�@P�L��$J,( p`, ‚`H2 L"=w|GrsZLt?慬v7ӓӥ5/X]bosd]ôy 8FX^gZ ־[Fnz65#Gx>J ?랼\ؤ4-sO9@ B�p� ����L�@�J& @PL DP$c^Vqs{ڬe\]LJOEǏu.i~n=Wf?c?]L?Qn>Ř<B59%s_ezi281* iiR%1L!P �p� �p��,�J,T!@X&  H"|Spw&T5<Jݩ!+QYd"^ 57^l?T;_jæU z:m `u3R+;c/2vQKO'N9 w�,��!P�"��� �H,4 b X(B Qc|.Y(^K܍cWԉ,v'Nz\~:?hF?`~Wj0u9\1{ۄo) �7?]=vpm6#)[Ev3�E �� �PT�J&0,D @T$2Ba<_]MꪵRFdEU˃W u.{Y9VޯD?M >rv> Ρ#Ou˟q~^7v=2Y\֠tlHܺzБ$/ED΀ ���*����@� �HW, `Xh H(% !0gqzʄTzw|XH[>4{Af.Ţ*_'Doo.n'~p,h-J^N?O `fwxs$%~~u1cQP)@ �@`��(���L&�Hhؑ21\ I~D/2>$^x Er5v`8|2κ?wj.$¾LO�؞UU*x}7? qfdPkU]0`d"HlGO2fw dif(��� ���7��o��8L (La"21%zƸھRYNǶ=o|Ʊy{_s\(#[wg{|X"ԚJ|kx|駺CU1VRZ6C3pSNW K, $=JK^Z]+RearAEۗh5uP\ dH�`@���  �pL, B0l `\* ,sxX\-.uJc')ҾsCUk~�g#_dթGߺ7-WC1=4,0Zh#|!1o 珜|f �,��P�� J( BcX(" p\*2 HaW<_4\n]$^.XS75;鲴mN q=?&V_g6yd_<j18M}i$D.NۣFbiH,;Uv%jZjڒc&@ w�  ���@.�@H.@(* BAPۍj]$V9sGO65Z;k}awMߡ{ 1럷ذK4?*Ƶ|.3g-G>I&nŜuk;c:JD� �@���\�D��J,D  ( @T(1)N}x<sRWU/N>^M^4g?~[s6--H~O/op+!U<q?5t^_JWd;Ք<D^E^z ٶ ^WSwxrb{ĥp�H � �� ���J&a@X(6 B0L"񾲫[k~w2Ie^R^kawzMZS_YF_37B; ZS !6ËF/>e1y6*:CgbYa}Rnr[:mW4yJUX]=-35e:`���0� �,�L �J&c h  H&S=rUFy*eHyoo/jfy|tm_1rUz!Wk mGY(mlbF=5ߵȳ6�m::][./<pUgN�2"��P@��D�� ��QpHLT A0P pT"[M_ڨnr%EFY󗗎do~w(QTCOK"+kh:8^;u"{G-Ǝ`_5A0-jyяljX[yBHl8ŕEKq܀���@�@��� �8FW, a H`X(% BpT"oV8%uܩs_bo?|h2 B~xkRIi3ƯdI 9#yGTh0m?tf\΢Rٜ\Kɣ䀹*QX)@,ÿ5cA-y�� @�����" �L&PZjP)< ͑4CLB}Nm/'Q|5u|*VzWUziepڃ\,JqG%wJcII@ KZ"ZPC4# ]X;q��5�� z���5���"�׬N-PΧӋI֖G{UJ$I[,o1.H)aJ+ ٢>< 'Ük.r%fv}곭='@3}�0zCb}Dj<ҋT8(0]ֲjZSs?6 hH́$ @�o���^���J& B0l @X* ,zf]q1)y*ƴI/CMg+9{1N ψŨyc`]\Q:8$)܋R̾1w>81<SC *oS}p%0� �`����,�HP*aA0(6 P$ X%]dVV&\*8=? xuY{wg VMYY"C48~)h*1J=Zc q@a𳽙gdTRfSc|~۩VKk[Lv@(��������H�pJ,D# @T(&  T$$ XβKS5u$rT9?~cUqݲG_jmH[u?nϝ]j4{8/>}.,[;~v_zGr;'oe?X%I.��"���@�`���J(*a ( @PJ BC@W[㚹Zqsp9;y_n٦t/qgwA*c K�qCz]iWKrfnPV=FT{7@?tN[>第׶l 0@� ���DP �8J,E A0P,@T( Fa@P"m9q Z[$?z\CvW?/?׵q~i~ίx~'uԌ {j]/ 8^ܝ{vPԱbfhɏvB$  �*0��@@ ���J,$ @,8 pX(!r[ʚ%%]͗Vӯ]{~U]/k^i^I4aKYH MZ-͇}y>.hSS1ұ):FJ[dS3u)U>mZ[k\�V�&���"�.���0�8H& a \, b`X( D&S5Ǎ1-fKqjI.O)ydO\J:6n#~|wxg-ZL�/$ï R]Ѡ1^8 X Y~SQFk2ؚ |V:(@.�PP� 0� �R �@LW,T A1LDPL"w(kTEBL2^ \#{(/==+y'n_+kZ9$$F~ m¯w"Ô~}<XKշ%,emzẗ]sH}\cČnٸ"EH�.��$��� ��DD,`kȲ(u�m RcY�/jlW OY'Eݖ4(#a ~(DیqMozI_7Bԧ!�DsM.u!=eYX4_\-ycS�d3Gnp^� pP�� ���a��T B�LhTbW~g׮�J(51xZua,JґuZx_][-diHu L~ɿcg+BQ ԕV^ IXYEDNXT,Qgnq(g򺴞=Ҿ3谌dz>&s���9E��pL( `XH& H( AA">f5)u&.Uͯ_ϞZF'[=^h]{qۣ7+|< [Պnm؉W_S|&9n: W,vߥM>,BN.G"Ic�p���`T �@��JH`H*  P$ BCP\2Baޓw_&oy̎yq޿u uN6Λ}v$c:psW.LGw˓oeWFg-C3M�|tjZ'|l*::,]-R`A1  f�!@��T��(�HLBa (& F@,%D)k5L&ƿo|7ݷ3;Gg,v| yB_GFGX>mQd ު8oٻo)?жbE;M5R��X�@�PP��� JW$ Bb8X( APD *7S֤U^yμ>櫥jO Ɨ޳J^=OPƽvD/k_{йnm0vxx+v|<c0!4Mw O/W 4gz)`7KLuc~~BP�b` �����$�FhXBaf~ֺTg;w|O3*xc7F!$7 J"ժ4dE6v$7#k�=x-x]g,cx::£nYň3[;)i Ωb#kOi%]^q<um]vn#׹|d0>�UJ��� P"���P���moof���mfhd����������traf���tfhd������������������trun��������������������������������������������������������������������������������������������������mdat���free����mdatFh\T13U8ֺ~%=<\Mi!|Ǻp:HȈg" CY_XؕYmQ N̅ ,${ޥeXˋz'qҨQ <wl*m<E;h:_\%p]>.aʤ|&G<6P�׬7 s�X��5��jL$,Q:2cHk|g39cbFi]Y)yeU@TS.��:gD"�4Ѧxz~duC|6;+֮j <o9]?9tl|]]G_'Z? }Odb-dT!H `yր�l;6��X�l������aN $j]R1q/?ky<xd`ʗ7D^ឪórnڤV 'y7%IW<ܧQjwXz,xܵ򩸖_Yq|c:O lE5F<m.S=:7#Ϻ�ժ��5 U����P @�@�pN $,PHƫۜ#]9[DQVxqe_VOK!yC'7jI=wtmeu%St97kݟ ڽD j*ZoRaCC{x$U˝!f?5[F;份u]˦| fG_�ur=Q�7�D@D&o�� ���GN ,`RdbT[\"]} | z%vg@<Fֺ:l8٣q| Mqt 7*<bm?n믉WGYu:4K"K:}^ �,B]4)ȫ"R؟E\+0�x��@�����N -q5]Z] l J\;RXah\;GM1k[rJq^7G{dHY ޻O(aOJ6E 7LfTw.`-( (LKN &@*|93ކ=N.YnT ���`� ��"�RH A@P* A`P$ RX0 Bbh[Zߏ=xo^tџso衚�=]`ϱaUonO5n<@u`1ŶHQa:,u{%aV_髨xj9O/tOumeK�����\JL B! H ApH* a&S~5/^2u<yu5|nur-O_tt?o+hԬm^yymcߘ13窍Y_WhPvпTN( �$6İ8=}p%n=RE7?*X1��X�X�P� ����pJ$ AC@X* A8T.6 ġ2 ʯ&?m+k:"?}ޔڻ:~eV:Q-𾯤*fh*]$@df>o_)Fմ7f]%0еYOV��@D�&���X���HL$C@XJ DPTNBaD&C}]޷9u^5-Ypv> \~6՞ʳnELn_l-wHܯʥ,Xdd߭QVBPVmqX./a.qϧ]q0� �� �`�L,( AA* X(' BP(:7s}s$ݳzq>3cɍû峣 m>CIhIFQA<,>OHTa'oj:~ {ۂmvK=F yz Ffmk rp�@��R����Hn`H& A(. #0=DsU^nnj_9Uܿ_qϧ gxzଜ!IˠWi /~>ʱ _ 'OgZќoQ:Rt.;`_biԷ^sL>EU�p�(�"�@�.��$�pHLD A(X(3 @\*0"UTwsסe_5ۛX<=<ǛXf:O_3~=P\>>5.`g LoTuՆe ~_ZRqUL]>@m ]ҡ� � �� �&��L� JLD#B`PL @ !1 Y.wml&I|y%԰t[[hˣmcwWygWGy˭YBHfi?A`Q<r3?ӡra[�Nqq`h�� (���`�&� �H(H& PT, pT& P{}k|ߟ޳5Zjrx썼Shظ YaAPu=Op;Vxn/#6E,א=e^¬$5d',o˱{ՅG ~rXHوJAc@ �� �H�@�J$  XD A, q(bxYd㙙uůr +C_QοoH/v=B}׹>뚇1bĝGe8=|e?/vlC<tnqƯjD؉33܋j+�`�� �\� P ���H( P$ ApP$ ¡`T$F+_{x;{jyu{|'%Ic;xu𵗵[_o}Dq.a_ZǪi`/i={TwQ4ُC<rz~YN|;t]uI9%je`)�@P� ���H�JF9A`PL% A@H. 2 ~}|s~}^j/˽'7-Iu- vOHLmӈ*>"~+,L-s?S?xU~>�RZ&}M(éW)*8w=} M,wQj_���p��p@��X�L$ !H( 0. BAP& B1 ~*~}7:殼ߝzGxMӌR m힐ړg_G0Fg=Op Iߤ~`\|j| ?SnSJGנ�z �$�*@*@��\�J( CQX* D \$ d$ BbP|㊞5g|Zm~?a~qǴ|g_O4r-#'G^LU#/'[ ˥f{QI[W! ->-oh+LgQ�w�s|`��� ��������LWL @d  T$PBڼߏ|ݒǼsܹKyq׃kѢ穚G]em}IԪ{}{8!P [v͘8ߓс*[@%/p ZI/��8�L ����T�L(Y)bԗY?z ,0CldT HFJtR +_:_}3x'y ԊʥxR̽L j7b'!oaPVi\:'՛tNkU$gnV5Ώ1g $ ��M0\*���Z��}��pF$ \%߷.Ht!1;]radTHk;f:oAs+mkԿ߇Ϻ<;kzn]Dv㍫)riۻ%UGUJA�L,� � j��8LI jz#WH_OzS '㸧KCaV%�nj ){oW^/YFqS7&O&|vrY|Z*dzȂWa/$ c����SP���!N ,`R3RM|ނXuÅ5_?BۯGY\5jNo|{aʊZ9h/~mK"`X*"`M1eIӳ,7SJ=`^ʃXH�.RL.�,��.��J ,Ъd`wu|X߈W1x_^rU'iW׏^{tq.6񷍿K~!AR՘ )NF* 9ux%Ct\%9.KgQɋ*a;,X <���* ��*����L(AP$ AP\* BaEs#YǞ7n$_kCtmW}0WmQV^�ʈ>I~ mƽ9%ݎ ӜEo5�H��&�"����@�H(&!`P$4 p*" Da337ϙ>$uJOO/>VП>[eN(fb_p~wdr�qk?`uPqGs/qcH8 �����p@��H��H$a!@h q &% DaEm\Իy]|SYu/%\#[;G .tLWsWZ|a\.^^J*b"NWǻ*il�L��@�$��� @����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/no-tags.flac����������������������������������������������������������������0000664�0000000�0000000�00000011124�12225024651�0017234�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������fLaC���"������ B�zAf鄚0 <w�,������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Y�k������Yl������Ye������eYb������)Yw������QYp������Z$Yy������cY~������YS������+9Y T������LY ]������Y Z������Y O������Y H������aYA������X YF������xY������gY������Y������Y������^vY������7Y�������-BY ������Y������Y#������\_Y$������*Y-������Y*������eY?������Y8������Y1������/kY6������Y ������FY!������i3Y"������Py#������XE��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/no-tags.m4a�����������������������������������������������������������������0000664�0000000�0000000�00000005522�12225024651�0017015�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000���������������������������������������������������������������������������������������������������������������������������������������������������������������������������ftypmp42����mp42isom��mdat��libfaac 1.24��B� 2�G!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#!�I�#���mdat��moov���lmvhd����EL�_���������������������������������������������@���������������������������������iods�����O��ttrak���\tkhd���EE�����������������������������������������������������@�������������mdia��� mdhd����EE��D�~�������!hdlr��������soun���������������minf���smhd�����������$dinf���dref���������� url �����stbl���gstsd����������Wmp4a���������������������D�����3esds����"���@���� �� b��� stts��������������������stsz����������������� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ��� ���(stsc�������������,��������������� stco���������� ����I����� ctts�����������������������udta���qfreehdlr��������mdirappl������������Lilst���!too���data�������FAAC 1.24���#ART���data�������Test Artist������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/no_length.wv����������������������������������������������������������������0000664�0000000�0000000�00000001024�12225024651�0017366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������wvpkh���������"V��!Bw!RIFF$ �WAVEfmt �����D�����data� ����������������e������Xwvpk4�����@~�"V��"V��!Bw�����������������Xwvpk4�����@~�D��"V��!Bw�����������������Xwvpk4�����@~�f�"V��!Bw�����������������Xwvpk4�����@~�X�"V��!Bw�����������������Xwvpk4�����@~��"V��!Bw�����������������Xwvpk4�����@~��<��!܉�����������������twvpk4�����@~�A�<��!܉�����������������t������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/noise.aif�������������������������������������������������������������������0000664�0000000�0000000�00000010460�12225024651�0016635�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������FORM��'AIFFCOMM�������e�@D������FLLR����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SSND��7��������(xc-ZL qK<< ZA- x�RZ<�i͖ XkjK=\<5<-K�xL  �[Z�<7 x < jx Ko - x (K~ P�k-w ZF)2Z :Ku<T<.-;x�$ - "DZGKs-giiY9I�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/noise_odd.aif���������������������������������������������������������������0000664�0000000�0000000�00000010457�12225024651�0017471�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������FORM��'AIFFCOMM�������e�@D������FLLR����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SSND��7��������(xc-ZL qK<< ZA- x�RZ<�i͖ XkjK=\<5<-K�xL  �[Z�<7 x < jx Ko - x (K~ P�k-w ZF)2Z :Ku<T<.-;x�$ - "DZGKs-giiY9I�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/rare_frames.mp3�������������������������������������������������������������0000664�0000000�0000000�00000020200�12225024651�0017737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ID3����eCOMM������XXX�A COMMENTTXXX���1���userTextDescription1�userTextData1�userTextData2TXXX���<���QuodLibet::userTextDescription2�userTextData1�userTextData2TCON������13WXXX������userUrl�http://a.user.urlWXXX���*����http://a.user.url/with/empty/descriptionUFID�����supermihi@web.de�12345678��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������VBRI� �d�bۑ��!:����@6λ7Ϻg7׻Ϲ,58cZO4ķccmY*0Eλ6p7 Ƙˆ8`h0h088�Ƙ8Ƞ�h�hȠع̻p˵}X,˻fh*e\ phƘƘhh�ƘƘȠ�8ȠȠhhp(7����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������D�����K���� p����.��� ��%��I� B2|P��m�H�PЮ  קNn``0�7(}xD!����K���� p����.��� ��%��?ݹVjƀ@��1V-܀ 3�o,ɿ@(kv<] �/DB����K���� p����.��� ��%��?Nnc%���� �Wy|J�B� [c�P��@��@��@�d>c����K�� i c�$� '�\=P�N8] E#Lu uT;`;W@RincKDdnt�~�ƨ���`=��l���:dp�ft7?AۑէV)GH4 -Ơ,扖"&&& �&&Gdʣo��HA`�),�L/�� Cp�)FF#�!`ƢPa <<p S$-+Lf@`;2Hd!k��'�ˠ@�)� � C��y&4[>mܤ A�u{ T " [Qb縓n'1dZAv���ƨ���(<��d)A%apr2c`kQ#��@�D"M$BBIłHC�Aa)h])dN__.a7?yqcKd SȚdCM dM?KYcl mg o1J̰~zeG L Jx@iɷi@3G ^BCL4L(b QVh2Q[:}8%`TȺ<cܐ\7TLr!{d2SS͛zey=~vwW39u=e.d9%}�PPfZ)ɟqXAK�� )g ix֖J�,z]N Xp q+Ed i+H?rUbFXF @!7K@tI#$^s^{uZfR@�VANPB6(�Ȳcbe2CؠU%lu�F3ޛkC:ϲO+lo.WevI ((,xK/)-)F!tҮ̿azLPV1t9d{O](TˉUݔ]A^+d`+h+E ꁬ.֤e gB}2`i)iN"G_P?VB]0[u!  ,4ظ1d2/=/I]4(IJKd yF,MyeǒUL$*v1"wL٣qf&܂.IdMZz.DD n0`g`7fBbrjF_XIÁ_,<E2}90T)&}׽>4q�,r&@'vek�F2ɅP߁#q3R-vB^Q2v,'; [O !iUxܪ#ڧm.BNV@|=`IФ@~&{;3/) 钕mH9JaNQ#HZ:@�@ V9.QVNOilMBCS%A8N"q9/ JDxד8W$DnFuͶYb317]Csmm'̙5"9 o2 $i BXi Zo 8ɠU@JQ jxEa?41 TJ`\[a aV6,�(1[^ ZŪV.MYe67圚xLgw�A¤3Dfgw28<YB627I :8,LdU^^Vd#UVS,<IzaS/S- c&IZpPaH۾ !VkI)AҋE9phਛ?ݨH֢BJ ʴkpJσä]2<LbOa齋em=50Rv[@׻вM S9{HGBٚf+ӝX# �i< @L1_t4\qf/ \hONꋇk+gU^K|]B"b*n~ߥ[/AgFTݫ/tY>C8=9%P5ݷڇ95V~RTI 1(|U'Wl)Y8 }Wf5sJ< ^V_ d1(S3QG[W„I M ZEZTMrůVkeXVae쉲cEoy C*nQ :Z]C�_8 2)HN5$xiP26 iBzQF*4{_.Պ‰EšJS}pW^uE>fSj+E讠mt u `OEҖQ+҄W3 wmj7m  ZTC-8do JSd<i =a@Q5�:;iR'#ȵ$[#*44Iأd d@<CpGlz?4|2D'%-(tk!9F_�a:#ǎBm2Uq1ngbd$^ 2>^<կ'Gĵ2IY.6MnH$AפQ4(H^7]dnf\ OVmc i3ו6ѩ(t/\ljgYj*fRյ5 k/11 ߯ qU3 ķzFŀq@eȭ.tfOrdLrwp,2g%_%v-5aT`lĪK@ηD +5#bY,fE7Zxq^ů֝=Yֵ=5^1-SFؽOLb )'CFdB)L`PL& j.z/LBSJ95H.Iı3 [ZS7LKq[LN1(SX 6(Q33zR <Vxk/ )_9'GtO|8mx<c5ۖS_�$LB5dy�sOno@�Ɖ:�)3U]�*r++PT0 C`(XHA% \ xTMt,f $bCt0p4 Y̻{L0=aU$EMxaЇFA"xKM˟F'2; RlRw9ͤa^PQ- e:.ԍ׃g8͇ʟH"v Nv}7*@Suڵ Z=844AӹK!.ݛ*Pm6q TPQv8PFbJ0"bl3TzՈC$>G*@cl~eA [X`Iy"M؍kHRSN{kgV.qpMGlrM(QEIe۾Ԅn{SnM Z^͛lasv1?s -1K)†;$KDJ ۷mﮆ =0V<�0# !FscyԞ  P6iFb|Qv8<aa*v̆m۞R˳2\nPv]l3_Y%IWZԹf+M5;g ]~!3SXs 3ݟfawׄ.`ѿbPǣN0&tӳw<-ei3E#&hԚbUdW)NO-Nj O-jW~k 21*=fl.um~j+Ƿ)RG3}3;;q?5+4CaͺXn[ވ"m k$I)#�j:a5dO�GS N:iڽa&5!Qeji$[351-F^RarXns4Z;-GCR8p\3kf{m,^#biR_j%InVF^ɮDO~ێ ,X3fnw�?JKS,Fp%ZFXH]a`RjKS:Rq(LXї/a-مM> P&\~(=P:,ZF4:Xa-^Cڎ1~*2qYubP� np=7ff- ! l!3z X8 {ae˱B`X1RQTgj[@b<xKT(Y8N⊤̐ 1m`z(Ur*(?kY-}O~[}hqC)iӥ pTddOqWrmF? D$ᮎIP sь[R3%C˒!ehpdUb 3%IQQi}ԦpQco$&Yf͈IKGF\ϘBIn0|@ q Z+a2�Z&d?MT Fh aTIY:P5& P"QɜfJJ pHk0 GU.Xd𣧞$ZqR9\8 0i KlHYTʤ%3k+3 4hvӶFFBhֳtxŚh6 MH}7=6aIǨ[X2Oc<Of{' @4e\`x~Җw*\s*);.cP?f?ŝ4l DbK=}!FE9o|$|6γ X:܉J,8ˁǒ,YIo(ڪl!NrTb<}'}SrE6p Z'bn$ABWS)(kXh sK*>NG$�j+2j &iwAޣK/]Y,2ܷouRENņln 2x$S&Žƒ.rxqobV1/#UJ@szpQ]I됣$aJhx)EHTawYeZ*3WKJFߎ1 Y~'�}YEMވ=zDdAC�LUS/LZʽ=)!U=3j9j[q]0gAG@eg `!44e#ud+'ӧE0WԷC.Iޚ(ˣ l laP4ijBˇr•#RWQWdȕdH$iߐ @Պ%Bt3 $%z|<Ǩ2ɨ4\�"DIMM-ąCǔFT--h/RHZҸCQ&%;ŻH"x^U֠q2C̖g(<i+5콡 H(RZ - Pp>Oq"\IKĜ3j 49*\]5LDp۹#MYS^҇dubh g#x;*H# !F]" OLѷI֗||+k:%&<!!P\#}0h�%�<c$XFҧ!$F<U6  z bay*K;L dl݌Ojc^qӡK1+Ն5KlruѸZV*®*V" mZ�Bp YhDü%84(D�e+Lhբ$Cw` AAf9\1Nߵ:z �NZq߂6Є -B?\d[1�"Mk,ȁHe}IW=5b()"`ʢ)N@9#yBޗxz( "i]XE_O1޾` YIl뭇ș3qkT�Def5ljʡB.XOY�JYͧW*-9gXmz 5gmL;$-: J$UbX΀ ]uıiOG]oC @V% KtQ$]gBk)Tc,-LFpOm. slG:Nw$kkoS3(ಪS.tzOH,]H5 iE1t B㇈t8=9vY,M{5+(Q lRXZ}`0m} HlE0kl h4 ̈+TAG���������������������������������������������������������������������������������������������� 00000000 00000000 00000000 �� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/silence-1.wma���������������������������������������������������������������0000664�0000000�0000000�00000105130�12225024651�0017324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������0&uf��blx���������3&uf��bl4������� �����t�e�s�t�����������ܫG� Seh�������CO;J)rJX������9.@ �����������<������������� �� ����_.� Se������ӫ� Se���FC|K)9>A\.��������s�k��� e�n�-�u�s���]&EG_eR�������ů[wHgDLz����������� �����I�s�V�B�R��������4������D�e�v�i�c�e�C�o�n�f�o�r�m�a�n�c�e�T�e�m�p�l�a�t�e���L�2���t E˖p����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������˥r2CiR[ZX��������������������������������������� �������.��������� ު|O(Uݘ"�����������������@�^P���������W�M�F�S�D�K�V�e�r�s�i�o�n������1�0�.�0�0�.�0�0�.�3�6�4�6����W�M�F�S�D�K�N�e�e�d�e�d������0�.�0�.�0�.�0�0�0�0��� �I�s�V�B�R���������@Rц1�H�������ARц1�H�����W�i�n�d�o�w�s� �M�e�d�i�a� �A�u�d�i�o� �9�.�1���$� �6�4� �k�b�p�s�,� �4�8� �k�H�z�,� �s�t�e�r�e�o� �2�-�p�a�s�s� �C�B�R����aܷ� Ser�������@iM[�_\D+Pÿa�� ���������������a���A�� � �����*�� ��u{F�`ɢ �����������6&uf��blv������CO;J)rJ ���������]����U���� ���� ��% "" w=  ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]U��U���� ������AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]��U���� ��+��(��AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]��U���� �� ��8��AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]U��U���� �� ��H��AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]��U���� ��+ ��X��AA" w=  ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]��U���� �� ��h��AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]U ��U ���� ����x��AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������] ��U ���� ��+����AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������] ��U ���� ������AA����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������]U ��U ���� ������AA" w=  ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/silence-44-s.flac�����������������������������������������������������������0000664�0000000�0000000�00000143330�12225024651�0020000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������fLaC���"���y�+ B�zbܷH2ĺJ��l������������������������������.L��������������8������V�������a�������������vL������������� ���reference libFLAC 1.1.0 20030126������album=Quod Libet Test Data ���artist=piman ���artist=jzig ���genre=Silence���tracknumber=02/10 ���date=2004 ���title=Silence�L1234567890123������������������������������������������������������������������������������������������������������������������������X��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������123456789012�������������������������������D������������������������������������������L��������X������������������������������������������z����������������������������������� image/png���A pixel.����������������PNG  ��� IHDR���������wS��� pHYs�� �� ����tIME  6D=2���tEXtComment�Created with The GIMPd%n��� IDATc?�Y����IENDB`� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Y�k?O?s???????9>?3y?̟>?O????ϟy??ϟ??'<3??O>I??Ny||??�C3'?????????????g|????s?|g?yg????|ϟ???'?'????9????sϟ>?'Oy?4uYl??93??>?ϟ?y3???O?y?????9?93???<<3O???<9ϓ???9?~O??g?~?ϞNO'�Cɟϓsϟ9?g'??|?ϙ?'?3|?'?????<????d????g???ϟ???>yϟ?g?9?<??~?9?I???ϟ?|??Ye?3??>|?gg??>|~s<?3s???''<~???O<??~Og????~yy?????g??O?9??g?ϙ?y???>y?|?�Cs|??N̟?3g???>sg?L??3O?3y???>3ϟ?'33?~||g???O?|g<??6Yb???s~y<??O?ϟ?ϟ?g?????ϟ ?s?s??<?g???|g$3?f?真?�Cy~Iϟ?'?'O<<?'&?O3>g~gg?ϟ?g>sϓ9?L><??g??<~?<?'3??g?XYw??gϟ?|?s??y??2g<s??|>g???????ɟ??s<g?<'?s|y>>|<??3g??ygys?s~~?????$s???y?g<???O3?y??3'??ϟ9?????9?O4Yp9???3s<'?????~<'?yy????g??ϟ????9?O?ɟ??>?9???3?? ?s|???93???????<O?fss??>?~g??'g???~g???3g?3??ϟ??s Yy???s?9ϟϟ9<?|???9??|>~Ϝ?yg?3???f3>??''???|?'????$??'>'?'9??9?9|y'|??|@O?<|??>3s??&~3???????<~r'??s~???'???s3ϟ??ϙ?9?|'?N<??Y~???O??'<?????O???9?????|''~?y???3>????s?????9??93<?|??ϒ?9?@?????3OI????O???&s????ϟy~'?<???<?O?~??<???<?|<3????gYS3y9?'?93??>?ϟ?y3???O?y????????<<3O???<9ϓ???9?~O??�Cg?<3'?9gy?s?~'?y??9y>?>O???3?9?y|'s?<9O?Ϟ|9?~?g?3???zY T?y??<>yIg9<3??>|?gg??>|~s<?3s???''<~?dϟy3?~Og????~yy?????g??O?9??g???~?3????|??'???O???>?'???f??'O>?>s3<?L??3O???s???ɟ???y<????y?9g??s<=Y ]&gO??|ys??g9?>~gO?~???<?<???y?ϟ?????3????9&9I93?g9>?|g<??y~Iϟ?'?'O<<?'&?O3>g~gg??ϟ?>sϓ9?L><??g??<~?<?'&Y Z???y??r??gϟ?|?s??y??2g<s????y??~?'??????ɟ??s<g?<'$9'?󟟟'|???>~?9~y?yO?g?'O<s's????O̓?$??9~?>???|||9??=Y O33y?99ϟy???3s<'?????~<'s???????g??ϟ????9?O?ɟ??>?9??'??'?y??y??9??39gsϟ'??|?ssO<3'??3???yϟd~?yϟ??3???~??O@1Y H?'?????>Ny?<N??~?Oys3?3ϟg???>s?>9?ssy|~???9?s'???~O9????'??|ϟ?|?II?D<<O?<|??>3s??&~3???9??<~r'??s~???'???s3ϟ??ϙ?9*YA???|'???3?sO?s???????9>??s????9<'??$?????ϟy??ϟ??'<3@?????~?|9>s~?9ϟϟs??????3?g?'?????9?????g>s|~|???~sO3kYF?g9?<???~g?<?'y??g?s>|y?>3?'g?OO??3??ϓs?>g?y???'??|<3????gyϟ?|'Oɟϓsϟ9?g'??|?ϙ?'?3|?'???ϟsO'gL?Oy????ϟ???>yϟ?g?9?<??~˛Y???>O??|y??<>yIg9<3??>|?gg??>|~s<?3s??ϟ?'??????dϟy3?~Og????~yy?????g??O?~?g?3??????s|??N̟?3g?'O>?>s3<9?s~??$3y???>3ϟ?'3Y'y3?~<gO??|ys??g9?>~gO?~???<?<??g?????ϟ?????3????9&9@|g9<'?3g???O?3O???'>?<?~?O??ϟgy9??>|?3ϓ?9??>L??93?<?ssY?$3?f?真?O<?y9ss<?<?????̙|?<??d?<????O?<?gOg~?>???'??s?�C~?<?'3??g?ϟN???????f????g?????$s???y?~?93>y?ϟ????$?<??y??Y'?s|y>??9?f~?????'~????'|?'3yy>??ϟ??><?3<'y<~>g?>3|>|?????|???|?fg???|?ssO<?y?g???ϟ|9?OOs??<?Y??ɟ??>?9???3????s?9ϟϟ9<?|???9??|>~?|ϟϟ~'?3??g?<~O???|?'????$??'???<<O?<|??>332g>????9??<~r'??s~???'???sY�?|?II???|'???3?sO?s???????'O??>?s????9<'??$?????ϟy?93ϟ??ϙ?9?|'?N<???????3OI????O???3?g?'|?yO9ϟy~'?<???<?O?~??<?VHY ?????9??93<?|??ϒ?9??瓞|3|?3'??3~ϟϟ?y3???O?y?????9?93???O?~>O?D|~|???~sO3?33O9>?s?9???r??s~rs?rs??'|?'?????<????d????g<>|?Y?9?~|<?g??3?<???'Oϟ????'??ϟL??|???|??~g>|?>s$??????3>I????s~~~~s?|9?~?g?3??????s|???>?'???f??'O>?>s3<9?s~??$3y???>i Y#'~yy?????g??O?9??g?ϙ?y???>y?|?9O|?????????>?'?<>?~?ϟ????'??O@3ϟ?'33?~||g???O?|g<??y~Iϟ?'?'O??3?y?|rg?|?ϟ?>sϓ9?L|Y$33??ɟy??????y??r??gϟ?|?s~s?9?>~y&>|?O??~|?y??~?'??????ɟ??<?ss|?O|9'?󟟟'|???>~?9~y?yO?g??~???O?<??s's????O̓?$??9~?>NY-?s<g?<'?s|y>??9?f~??y332?'????'|?'3yy>?y??3'??ϟ9?????9?ϟ???ϟ?'?ϟ?<O?393???????<O?fss???gs'???>pY*???ϟ?rg&|??Or<?Ϟ?39?g>>??Oys3?3ϟg???>s?>9?ssyOϟ|?????|ϟ??>O9?s?|??O????9??~<?3?????????9???̙ϟ<y~|???>O39???gg3Y?9???ϟ????39???9?????<?9???????9>?3y?̟>?Oϟs???'???s3ϟ??ϙ?9?|'?N<???????3Oϟs??????3?g?'|?yO9ϟy~'?<???<?O?:xY8???>????3?>s9O̜??'?3~gO?y9?'?9??3~ϟ???O?s?g?sLy?????<|@y?'??9??y?y9?????39??<g?<3'?9gy?sg'??>gO?3??9?y|'s?<9SY1??~>O?9?~|<?g??3?<???'Oϟ????'??9ϟ??ϟ|??~g>|?>s$??????3>I??�C>?9ɟϟ??y?yϟ'??>?~?3????|0|??N̟?3g???>sg?L??3O???s???Y6'??s??|ϟ<gy??|ys??ϟ?????~?????ɟ???y<????y?9g??s?ɜy|??'s??~Iϟ?'?'O<<?'&?O3>g~gg?ϟ?g3??>OY ?Oy????d3??ɟy??????y??r??gϟ????|3?~s?9?>~y&>|?O??~|?y??~?'???@?9??>L??93?<?ss|?O|9'?󟟟'|???>~?9~y?<~g???~???O?<??s's????O̓?$??9~TY!9???Oϟg'?~?9'?sg??9~g??9??s 9?f~?????'~?~y??????�C?>???|||9???'??'?y??y??9?|>|?????|???|?fg????????9>3'??3???yY"<?g??ϟ????9?O?ɟ??>?9???3????sϟ??'|sgg3|ϟϟ~'?3??g?<~O???|?�Bg??'g???~g???3g?3??ϟ??s???????????????ϟ?|ɟ??<?y?y#��jUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUPTUU*UUUtTUWҪUU]UUURUUU]UU]RꪪuҪWUUUUU]UUUUWUUUUUUwUUtUUjUUUUtUUrҪuUUUUUUURUUUT]UU\uUʾUWʪUUUUrꪪUU]U)URRUUUUU%UTUUUUUWUUUUU*.UUUUVUU]UjUUUU]U*UU*UW*uUU]URUW]UTUUUJUU]jU*U.ꪪUU]UUUUP��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/stripped.xm�����������������������������������������������������������������0000664�0000000�0000000�00000001132�12225024651�0017233�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������title of song������������������������������������������}�� ����@����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/sv4_header.mpc��������������������������������������������������������������0000664�0000000�0000000�00000000200�12225024651�0017553�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������' ��.'RK߷S1fYLbeYe1B ,hn ^ٕh3隩*\˳K|9vqZr+dՏ؉�ZG,܋LvkJÜ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/sv5_header.mpc��������������������������������������������������������������0000664�0000000�0000000�00000000200�12225024651�0017554�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/ ���v�ư@RJ)mj)fc,1B,Fc./y<a6WzDuu6W[_wywgrJW\ʘ+?=k ^]qmH7I������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/sv8_header.mpc��������������������������������������������������������������0000664�0000000�0000000�00000000162�12225024651�0017566�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������MPCKSH*)^�RG E}ZE}ZEIQ�SOD����APAPAPAPAPAPAPAPAPAPAPAPAPAPAPSTSE��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/test.it���������������������������������������������������������������������0000664�0000000�0000000�00000001204�12225024651�0016350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������IMPMtest song name����������������� ��0}�������Nd @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@���D������4�������>Y ��>"3 ��>��IMPS�������������@�@This is a sample name.������������������ ����������������IMPS�������������@�@In module file formats������������������ ����������������IMPS�������������@�@sample names are abused����������������� ����������������IMPS�������������@�@as multiline comments.������������������ ����������������IMPS�������������@�@ ��������������������������������������� ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/test.mod��������������������������������������������������������������������0000664�0000000�0000000�00000006074�12225024651�0016525�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������title of song�������Instrument names���������@���are abused as������������@���comments in��������������@���module file formats.�����@���-+-+-+-+-+-+-+-+-+-+-+���@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@����������������������������@�����������������������������������������������������������������������������������������������������������������������������������8CHN����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/test.ogg��������������������������������������������������������������������0000664�0000000�0000000�00000010470�12225024651�0016515�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������OggS���������ۿ;����Zfvorbis����D�����������OggS����������ۿ;���9<a}vorbis���Xiph.Org libVorbis I 20050304������unicodetag=öäüoΣø���unusualtag=usual value���unusualtag=another valuevorbis%BCV�@��$s*FsBPBkBL2L[%s!B[(АU��@��AxA!%=X'=!9xiA!B!B!E9h'A08 8E9X'A B9!$5HP9,(05(0ԃ BI5gAxiA!$AHAFAX9A*9 4d���((  ���@Qqɑɱ  Y�����HHH$Y%Y%Y扪,˲,˲,2 �H��PQ Eq Y�d��8Xh爎�����4CS<GDTU׶m۶m۶m۶m۶m[e Y�@��if0BCV���0ĀАU��@��J 9ߜYJ9Hy9s19眢Y 9ĠY 9'yК*9q`9&y9iK9HyRK9s9s99眨9Oޜ9s9s9 4d���@a)h Fb2A0 Bh:%qRJ' Y���@!RH!RH!b!r)J*2,2,:쬳; 1C+RSm5Xk9皃VZkRJ)R BCV� ��BdQH!b)r *АU�� �����O%Q%Q-25SEUueזuY}[؅]}}uaXeYeYeYeYeY 4d���� BH!RH)s9$ Y������pGqɑI$K$,O4O=QE4U]Q7mQ6e5]S6]UVmWm[uۗe}}}}}]BCV���:#)")8$I@h*�@�@��(8$I%igy陞*@h*���@������xxx舒h+ʦ캮뺮뺮뺮뺮뺮뺮뺮뺮뺮뺮뺮 �$��t$Gr$GR$ER$GrАU� ���1$Er,4O4O==SEWtАU�� ������� ɰM%R-US-RESUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUM4M Y ��S--ƚ $bjc R쥱H*g1^Q{$cA-)&TBc*RR 4d�p@,@,�������4 <4�������$M,O4�������������������������������������������������������������������@4@<@<�������<<D�������,4<Q�������������������������������������������������������������������@4@<@<�������<D<�������,<Q<������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������`!"��pH$ HM4eAӠi0M����������$MA �IӠi4"����������AӠiEi4hD����������4!E&3M"D ������������������������p��0 "��p8e�8��X��X%��`Y(������������������������������������������������������������������p��0 ��p(eDZ,8$ɲ�<D���(p��ASbqBCV�Q��ű,MEi'$I<Oiyi<4!hEQ4Mi*0MU��P��`��B�bYy'$I<OE4MSUIy(i,M<QETUUy(i<OE4Uuy'hEQ4MTMUu] i DOMSU]u牢i.MTUUu]Yi2@UUu]W뺲 PUu]Ye�뺲,����*ф @!+(��S0&!$B&%R RR)TJ*%Rj)UR) B*%R��؁�؁PhJ� �0F)sN"c9'R1眓J1sI)s9礔9sRJs9)s9眔RJsNJ)%A'9��T��`#A�R� cYyh$iy(&Iy'<OE4Uy(i*E4MUU],i0MTUu]i.l[UUue꺲 \ueٖ,ڲ���VG8) ,4d%��@B!eB !R ��p��0 �H��Zk@gZkZkZkZkRkZkZkZkZkZkZkZkZkZkZk-RJ)RJ)RJ)RJ�U8�?ذ:IX`!+p��s B)T1tTZB1$ZlsA(!b,sB))VcQ)RRJ-XJRJX1ZbI)Z1#lMjck*-c_dl-j #[,-Zk0[1>R,1\��w�D3$� � R1s9R9sBT1ƜsB!1sB!RJƜsB!RsB!J)sB!B)B!J(B!BB!RB(!R!B)%R !RBRJ)BRJ)J %R))J!RJJ)TJ J)%RJ!J)��8��A'Ua BCV�d��R)-E"KFsPZr RͩR $1T2B BuL)-BrKs���A���3��stG� DfDBpxP S@bB.�TX\]\@.!!A,pox N)*u ����� ���\�adhlptx|������|��$%@DD4s !"#$������ ���������OggS�z�����ۿ;���f}[� ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/test.s3m��������������������������������������������������������������������0000664�0000000�0000000�00000001040�12225024651�0016434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test song name��������������������� �SCRM@}0�����������      �������������������������������������������������������������������@��� ��������������This is an instrument name.���������������������������������@��� ��������������Module file formats�����������������������������������������@��� ��������������abuse instrument names��������������������������������������@��� ��������������as multiline comments.��������������������������������������@��� �������������� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/test.xm���������������������������������������������������������������������0000664�0000000�0000000�00000012537�12225024651�0016373�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Extended Module: title of song�������MilkyTracker ����������}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ����@����Instrument names��������(�����������������������������������������������������������������������������������������������������@� �@������������������������������������������� � � �������������������������������������������������������������������������������������@����Sample����������������������������@����names�������������������are abused as�����������(�����������������������������������������������������������������������������������������������������@� �@������������������������������������������� � � �������������������������������������������������������������������������������������@����are sometimes�����������comments in�������������(�����������������������������������������������������������������������������������������������������@� �@������������������������������������������� � � �������������������������������������������������������������������������������������@����also abused as��������������������@����comments.����������������module file formats.��������-+-+-+-+-+-+-+-+-+-+-+��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/unsupported-extension.xxx���������������������������������������������������0000664�0000000�0000000�00000000400�12225024651�0022203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/unsynch.id3�����������������������������������������������������������������0000664�0000000�0000000�00000000500�12225024651�0017121�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ID3���0TIT2���5����M�y� �b�a�b�e� �j�u�s�t� �c�a�r�e�s� �f�o�r� �m�eTPE1�������N�i�n�a� �S�i�m�o�n�eTALB�������1�0�0�%� �J�a�z�zTRCK�������0�3TLEN���@���2�1�6�0�0�0 �H�����I���� ,����^%��� >}G˿5�0}KR"J\ĻC圂g������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/w000.mp3��������������������������������������������������������������������0000664�0000000�0000000�00000001000�12225024651�0016134�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ID3����%COMM���W���eng�Promo Only - www.promoonly.com - Distribution of this file is strictly prohibited.TBPM������128TCON������(3)TENC������Promo Only OnLineTIT2��� ���Knowing YouTMED������004099TPE1������Sergio Galoyan f. Tamra KeenanTPUB������RobbinsW000�����lukas.lalinsky@example.com____TRCK������1TALB��� ���Knowing You���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/xing.mp3��������������������������������������������������������������������0000664�0000000�0000000�00000020020�12225024651�0016416�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������d�u�=�@��"`�1 @�?˼N(|rrDO xKإ2Mw3ŕQv. sR܄$dyA�� 0�#����4�`��� ADYa ^O-c7 EbJ!SwukrA%5:=ʹjw0l%RPn@MD] uؕd oA`�� 0������=� ���[[6mes| !)V+ -.Xڤ4ϹR[" !mdj���0�����<� ���=|TVYrK>͎pu1D{-eRa7tfTb)JT*vdkB�@���0����=�`���PTdZOz SGm=F*=)2gK̘Y +ci7bpynd dA@�� `0������0�a����U^!62z)}H:]X7NqUlλcjk)h{ech辅*kTd(jA@�� 0������8 ��{T:TVuw0QlKJ48'ދ}D9<!cW=vEFbJd/z��� 0�����9� ���\E7i*of81CQIxD1,Q,<_/m u,V)JȆݕZkU d6SB�@�� 0������7 ��o*ikP)U1u(1wR+TQԠt뻋<޻ j29N؄[Jd>lB�`��` ������5 ��� صĨ3`:4\ȴ"bY Ӟ"0-d/uҥmguΔB(tndEyA�� 0�#����4� HG*P̿b7xxrmCMMm*̺t A"(BT.?8EdK`�@�� ������: Hm~˩2 NPrYЪ1E叼XRZa饔ƠmV߲-C8غdQz��� @0���P@�8 ���In͠*Y#V$.9sgnF̛?ԺbR\Vko*U(VIi{dXXA@�� `0�����/� ���,`rј MvX*<>YLzJ1ץ/;  ]&up+C dbz��@��@��t���:� ���:D\=XYzSsWN}x^w]!F U̐FY׭$FЁte Q;1F!-UPYoLdgt�A� �����4 ���j6VӔ*{۟8^(rm&^HXRFKA"Դð"j#:* dmv��� 0������2�`��̯ar-Xʱ+84ΕT1XqǸQs醘–ݩKe+ ]S*cRduuA��@ �"����- ���|Au�Oހom61W�Ϩp9 Xѵ9}$KS<Ӹ啇Bd|`��@�� 0������5 iud5'2haµ2$!/&p4  vZc9frdf�@�� �����;`@��M93bRqό]͹(u2"*+bխǘ?C\(tsKըV6']9[h;s=PdqA��  �����.�`��B2ELv<FT!ϩ$%smNwzj ` L$`SqcbdoA�� �#���= ���0F?xņ^aW+5B.cHyV)Bބҩ4U sYz!㏋]ja{ֳ`6pd^A`�� ` �����9�`��pKPlw4i= [qUJ1*rv_\VjE."ذ쐆+ lґn`ddA@�� @ ��@�=�`��ƺ#kQqU)8YкQI4 wUk.M R 5;Y;Rdz���� 0�����; ��� EzQuVTqW9v ^ر}N~HX|\6JyyNg0Udu���� `@������+�!����E5Nb2@m 9HFG.9WlutBihU K֭3N2 1o - #{SdfA���`0����3 ���zǦ^Tk QMI(M@@εxs 4uk=DP~53FW`Tx[<dzA��� 0�����1`���ʣ#AMoc.ʪIKn5P45+8?emלYww1q@$T)q.d\B�`�� 0������;�`��MBp*Pɫ֊iN7*d^D| aҟ(F~h[zQHͭHiy"dǏsA�`��  �����7�`��Ezv*S{^[byU k C'-[VHVQO?UBQQW̉M (7fApbŲ1w Yd͏iA���0������7`���04B4U[d7&?%sْ6|G|1/k{&]i˥)Ghl6>6dgA���  #&��<� ���(krqt))G yN Jlz C)Ňʹ3*79xdrA���@������3 ��h(Uƚ,r ET7_۰}L)!!I;Ifw=p^S _do����0������-�a����mWIn qѭ =gy+0V̪'L9 (ֵHsoZkklh0,T>d��@���#�A���9`���Y̎\fmy$'@WHbFbVyၢڌqel) g jd�����c�B(���G�`@�z'8jF@, ZY&&BrVI킡g?]}vwo:-[<R`dyA��0#8�@�8`��dI*T ؒ@τ(!rP:tTPU[аu~&$>8VJd� ���A`�?� @1i2iy/9q]UB Lː8bF@SX2r˫w~xyd���� ������C�`���wlx:iL)_d(fcSIKi&=A׳mR_|(ed@����B<@?�`@��t ;L&jVy#<Njkߒn_h=V瘦LcZ$Cd}��� #&P)DD`@��R]sq%k֢9KݗE~ A<t֨A䅥/4ZzMK,z2dA���#8@�? ��˽{<l|?hu>3|2mbb6STÙ vm <e(d6>*Ld���� ���B\�@Hx('p( i^ZÝNF 9<o!d}T\e-BdA��` �"�`�A�`@��qA!ր(}y V4<Gt3yM{G׻k+:lg%M&dwA��� #8\�L� @v틨>5 ^A)xf.pnJk*X|ukh}&dj����  �#�P`H`@�?l5=F93/`tIi&4͇aQr__{Pd� � #8A`�4�`�,1{o:+ile.Yn B)VdV2R.y˸^X-sgʿQd�`��A��:`���krFRN;vuHe8C-6*IlxH<+lqL|貔p9rKd@�7#$ �E`@��;}LPF͇ cLcZFVS:Vޛ :4*&⬏m@d@`��� ��C`��.]P iUM2sT0q  i00+&ctdC4dYhQ" d@����B ���G�`��Feڻ̿UU |[,aRmj"l 2<7H[2w2Ċ<uJd@�@ #8���I� @��N*Ne<}^qG_Q./My};(Bs.&Rd~��@�� ��8��N �c]Zx)jm6Dle(At: w)SEt4\95h{uOAQ !dmA��� #8h��H� @ :IgނYY;* }ܶlIr.;Ww{F=/ =MCdA���  #$ ���I� @��eG&/j7 (ʚ_](y9 b(.hRS⡋ k>,FXjqPldA��� 0���T��J� @��&Tִw&igE2l]Hkuu%ԉ45Լx,Yd����` �"����F� @�NJ(ʞPmUF@*vJC7wl;x`v'.X"eg81d@�"8��D @���.o&Sdɭ"+]"'סyh ...lP)C>AXSjHtXd��A�#&B$���F�`@�!aκ^Y%ϵC([uB7kCb]Ej)Zy iA&=*+isOd~����� ���D����I� @��R<6N-/ۀ;,?'jYMʃBBŦ^OJViMdA�0���\�J� �qnat9B QzU .*4Ir9<uof~ub+<ɔC-);Od~A��@0����?`��HB\)KmUE m \XcU)RJbQ"\(<:>X(Y_ed���` �� @�E� s-^8ysK!qVd:@(BR)`7,s8Caf%&\M ҙd����@��c�B$���<`���R[O*Y+T9<�v)iWj+nyuk1朗k8;,kv}?9_ldA��� ���$���E r>Ol]ڹ~ *zXA׵.JE񖔧LBjԊm,L> G{zM37d}�@�� ��p`M�`�"o㯘wș6sz}ۈ Kf( SIsݼ`vlYA&P]UE.d���`#&��@ ��mF m|MmQ7R;A-EkDEڻ5[tjwShCbI8_BdA��� ���B @�D`@�s+;)3gӭD o\kxFaeE`PjtikFiJr hqqZUdA������P`J @\t-{onAŚ[Zzw])SL"0_:y?RƤpo%owxRid�� ���(@�@ ���;o-)dy2U zBfQ ԲH׹'Զ0,fG6R̙TTR7d@�� ��BD��H @��9 0vPW6ANufm( r-x5ZuY#nʽ̎b@dA�@�� `���8�L�`@��၃d�bD-|r$$XJP-Yȓ29>IT7bkȏ)J:ud�@��@��$���I� ��jA/._Z0XY\J5*ck qΕk73}MUߺǨQ X duA�� ���A@�H`@�=k!g\/d,fg19ԭ <H,!y!vp"v1bInMsw>׿td������"�B @�H @�/Mc2G~M Pj]4iu`pAPB]1/75A�R%Qހ<xUdpA�� @�p@L`� pv8b*ӲyÈ NCOϣRc;ooAԤ}8sg^Xj_dA��� �#�`�?�`@��#i2Vt2KڅYas$Aık9ʠ)g/0wG_5ta c6d�@#�B$`�F�`@�U!.=j]| w8[e)l^lIDpUUrӣ+Uѭ35e)r76<d���� "���E� @��yOXing����B@�B@����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/data/zero-size-chunk.wav���������������������������������������������������������0000664�0000000�0000000�00000002000�12225024651�0020602�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������RIFF���WAVEfmt �����D�����data������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/main.cpp�������������������������������������������������������������������������0000664�0000000�0000000�00000003116�12225024651�0015556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <string.h> #include <fstream> #include <stdexcept> #include <cppunit/TestResult.h> #include <cppunit/TestResultCollector.h> #include <cppunit/TestRunner.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/BriefTestProgressListener.h> #include <cppunit/CompilerOutputter.h> #include <cppunit/XmlOutputter.h> int main(int argc, char* argv[]) { std::string testPath = (argc > 1) ? std::string(argv[1]) : ""; // Create the event manager and test controller CppUnit::TestResult controller; // Add a listener that colllects test result CppUnit::TestResultCollector result; controller.addListener(&result); // Add a listener that print dots as test run. CppUnit::BriefTestProgressListener progress; controller.addListener(&progress); // Add the top suite to the test runner CppUnit::TestRunner runner; runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); try { std::cout << "Running " << testPath; runner.run(controller, testPath); std::cerr << std::endl; // Print test in a compiler compatible format. CppUnit::CompilerOutputter outputter(&result, std::cerr); outputter.write(); char *xml = ::getenv("CPPUNIT_XML"); if(xml && !::strcmp(xml, "1")) { std::ofstream xmlfileout("cpptestresults.xml"); CppUnit::XmlOutputter xmlout(&result, xmlfileout); xmlout.write(); } } catch(std::invalid_argument &e){ std::cerr << std::endl << "ERROR: " << e.what() << std::endl; return 0; } return result.wasSuccessful() ? 0 : 1; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_aiff.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000001214�12225024651�0016573�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <string> #include <stdio.h> #include <tag.h> #include <tbytevectorlist.h> #include <aifffile.h> #include "utils.h" using namespace std; using namespace TagLib; class TestAIFF : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestAIFF); CPPUNIT_TEST(testReading); CPPUNIT_TEST_SUITE_END(); public: void testReading() { ScopedFileCopy copy("empty", ".aiff"); string filename = copy.fileName(); RIFF::AIFF::File *f = new RIFF::AIFF::File(filename.c_str()); CPPUNIT_ASSERT_EQUAL(705, f->audioProperties()->bitrate()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestAIFF); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_ape.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000002762�12225024651�0016444�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <apefile.h> #include "utils.h" using namespace std; using namespace TagLib; class TestAPE : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestAPE); CPPUNIT_TEST(testProperties399); CPPUNIT_TEST(testProperties396); CPPUNIT_TEST(testProperties390); CPPUNIT_TEST_SUITE_END(); public: void testProperties399() { APE::File f(TEST_FILE_PATH_C("mac-399.ape")); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } void testProperties396() { APE::File f(TEST_FILE_PATH_C("mac-396.ape")); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } void testProperties390() { APE::File f(TEST_FILE_PATH_C("mac-390-hdr.ape")); CPPUNIT_ASSERT_EQUAL(15, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestAPE); ��������������taglib-1.9.1/tests/test_apetag.cpp������������������������������������������������������������������0000664�0000000�0000000�00000007162�12225024651�0017137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <tpropertymap.h> #include <apetag.h> #include <tdebug.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestAPETag : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestAPETag); CPPUNIT_TEST(testIsEmpty); CPPUNIT_TEST(testIsEmpty2); CPPUNIT_TEST(testPropertyInterface1); CPPUNIT_TEST(testPropertyInterface2); CPPUNIT_TEST(testInvalidKeys); CPPUNIT_TEST(testTextBinary); CPPUNIT_TEST_SUITE_END(); public: void testIsEmpty() { APE::Tag tag; CPPUNIT_ASSERT(tag.isEmpty()); tag.addValue("COMPOSER", "Mike Oldfield"); CPPUNIT_ASSERT(!tag.isEmpty()); } void testIsEmpty2() { APE::Tag tag; CPPUNIT_ASSERT(tag.isEmpty()); tag.setArtist("Mike Oldfield"); CPPUNIT_ASSERT(!tag.isEmpty()); } void testPropertyInterface1() { APE::Tag tag; PropertyMap dict = tag.properties(); CPPUNIT_ASSERT(dict.isEmpty()); dict["ARTIST"] = String("artist 1"); dict["ARTIST"].append("artist 2"); dict["TRACKNUMBER"].append("17"); tag.setProperties(dict); CPPUNIT_ASSERT_EQUAL(String("17"), tag.itemListMap()["TRACK"].values()[0]); CPPUNIT_ASSERT_EQUAL(2u, tag.itemListMap()["ARTIST"].values().size()); CPPUNIT_ASSERT_EQUAL(String("artist 1"), tag.artist()); CPPUNIT_ASSERT_EQUAL(17u, tag.track()); } void testPropertyInterface2() { APE::Tag tag; APE::Item item1 = APE::Item("TRACK", "17"); tag.setItem("TRACK", item1); APE::Item item2 = APE::Item(); item2.setType(APE::Item::Binary); tag.setItem("TESTBINARY", item2); PropertyMap properties = tag.properties(); CPPUNIT_ASSERT_EQUAL(1u, properties.unsupportedData().size()); CPPUNIT_ASSERT(properties.contains("TRACKNUMBER")); CPPUNIT_ASSERT(!properties.contains("TRACK")); CPPUNIT_ASSERT(tag.itemListMap().contains("TESTBINARY")); tag.removeUnsupportedProperties(properties.unsupportedData()); CPPUNIT_ASSERT(!tag.itemListMap().contains("TESTBINARY")); APE::Item item3 = APE::Item("TRACKNUMBER", "29"); tag.setItem("TRACKNUMBER", item3); properties = tag.properties(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), properties["TRACKNUMBER"].size()); CPPUNIT_ASSERT_EQUAL(String("17"), properties["TRACKNUMBER"][0]); CPPUNIT_ASSERT_EQUAL(String("29"), properties["TRACKNUMBER"][1]); } void testInvalidKeys() { PropertyMap properties; properties["A"] = String("invalid key: one character"); properties["MP+"] = String("invalid key: forbidden string"); properties["A B~C"] = String("valid key: space and tilde"); properties["ARTIST"] = String("valid key: normal one"); APE::Tag tag; PropertyMap unsuccessful = tag.setProperties(properties); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), unsuccessful.size()); CPPUNIT_ASSERT(unsuccessful.contains("A")); CPPUNIT_ASSERT(unsuccessful.contains("MP+")); } void testTextBinary() { APE::Item item = APE::Item("DUMMY", "Test Text"); CPPUNIT_ASSERT_EQUAL(String("Test Text"), item.toString()); CPPUNIT_ASSERT_EQUAL(ByteVector::null, item.binaryData()); ByteVector data("Test Data"); item.setBinaryData(data); CPPUNIT_ASSERT(item.values().isEmpty()); CPPUNIT_ASSERT_EQUAL(String::null, item.toString()); CPPUNIT_ASSERT_EQUAL(data, item.binaryData()); item.setValue("Test Text 2"); CPPUNIT_ASSERT_EQUAL(String("Test Text 2"), item.toString()); CPPUNIT_ASSERT_EQUAL(ByteVector::null, item.binaryData()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestAPETag); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_asf.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000021041�12225024651�0016437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <tpropertymap.h> #include <asffile.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestASF : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestASF); CPPUNIT_TEST(testAudioProperties); CPPUNIT_TEST(testRead); CPPUNIT_TEST(testSaveMultipleValues); CPPUNIT_TEST(testSaveStream); CPPUNIT_TEST(testSaveLanguage); CPPUNIT_TEST(testDWordTrackNumber); CPPUNIT_TEST(testSaveLargeValue); CPPUNIT_TEST(testSavePicture); CPPUNIT_TEST(testSaveMultiplePictures); CPPUNIT_TEST(testProperties); CPPUNIT_TEST_SUITE_END(); public: void testAudioProperties() { ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(64, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate()); } void testRead() { ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); CPPUNIT_ASSERT_EQUAL(String("test"), f.tag()->title()); } void testSaveMultipleValues() { ScopedFileCopy copy("silence-1", ".wma"); string newname = copy.fileName(); ASF::File *f = new ASF::File(newname.c_str()); ASF::AttributeList values; values.append("Foo"); values.append("Bar"); f->tag()->attributeListMap()["WM/AlbumTitle"] = values; f->save(); delete f; f = new ASF::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(2, (int)f->tag()->attributeListMap()["WM/AlbumTitle"].size()); delete f; } void testDWordTrackNumber() { ScopedFileCopy copy("silence-1", ".wma"); string newname = copy.fileName(); ASF::File *f = new ASF::File(newname.c_str()); CPPUNIT_ASSERT(!f->tag()->attributeListMap().contains("WM/TrackNumber")); f->tag()->setAttribute("WM/TrackNumber", (unsigned int)(123)); f->save(); delete f; f = new ASF::File(newname.c_str()); CPPUNIT_ASSERT(f->tag()->attributeListMap().contains("WM/TrackNumber")); CPPUNIT_ASSERT_EQUAL(ASF::Attribute::DWordType, f->tag()->attributeListMap()["WM/TrackNumber"].front().type()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(123), f->tag()->track()); f->tag()->setTrack(234); f->save(); delete f; f = new ASF::File(newname.c_str()); CPPUNIT_ASSERT(f->tag()->attributeListMap().contains("WM/TrackNumber")); CPPUNIT_ASSERT_EQUAL(ASF::Attribute::UnicodeType, f->tag()->attributeListMap()["WM/TrackNumber"].front().type()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(234), f->tag()->track()); delete f; } void testSaveStream() { ScopedFileCopy copy("silence-1", ".wma"); string newname = copy.fileName(); ASF::File *f = new ASF::File(newname.c_str()); ASF::AttributeList values; ASF::Attribute attr("Foo"); attr.setStream(43); values.append(attr); f->tag()->attributeListMap()["WM/AlbumTitle"] = values; f->save(); delete f; f = new ASF::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(43, f->tag()->attributeListMap()["WM/AlbumTitle"][0].stream()); delete f; } void testSaveLanguage() { ScopedFileCopy copy("silence-1", ".wma"); string newname = copy.fileName(); ASF::File *f = new ASF::File(newname.c_str()); ASF::AttributeList values; ASF::Attribute attr("Foo"); attr.setStream(32); attr.setLanguage(56); values.append(attr); f->tag()->attributeListMap()["WM/AlbumTitle"] = values; f->save(); delete f; f = new ASF::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(32, f->tag()->attributeListMap()["WM/AlbumTitle"][0].stream()); CPPUNIT_ASSERT_EQUAL(56, f->tag()->attributeListMap()["WM/AlbumTitle"][0].language()); delete f; } void testSaveLargeValue() { ScopedFileCopy copy("silence-1", ".wma"); string newname = copy.fileName(); ASF::File *f = new ASF::File(newname.c_str()); ASF::AttributeList values; ASF::Attribute attr(ByteVector(70000, 'x')); values.append(attr); f->tag()->attributeListMap()["WM/Blob"] = values; f->save(); delete f; f = new ASF::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(ByteVector(70000, 'x'), f->tag()->attributeListMap()["WM/Blob"][0].toByteVector()); delete f; } void testSavePicture() { ScopedFileCopy copy("silence-1", ".wma"); string newname = copy.fileName(); ASF::File *f = new ASF::File(newname.c_str()); ASF::AttributeList values; ASF::Picture picture; picture.setMimeType("image/jpeg"); picture.setType(ASF::Picture::FrontCover); picture.setDescription("description"); picture.setPicture("data"); ASF::Attribute attr(picture); values.append(attr); f->tag()->attributeListMap()["WM/Picture"] = values; f->save(); delete f; f = new ASF::File(newname.c_str()); ASF::AttributeList values2 = f->tag()->attributeListMap()["WM/Picture"]; CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), values2.size()); ASF::Attribute attr2 = values2.front(); ASF::Picture picture2 = attr2.toPicture(); CPPUNIT_ASSERT(picture2.isValid()); CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture2.mimeType()); CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture2.type()); CPPUNIT_ASSERT_EQUAL(String("description"), picture2.description()); CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture2.picture()); delete f; } void testSaveMultiplePictures() { ScopedFileCopy copy("silence-1", ".wma"); string newname = copy.fileName(); ASF::File *f = new ASF::File(newname.c_str()); ASF::AttributeList values; ASF::Picture picture; picture.setMimeType("image/jpeg"); picture.setType(ASF::Picture::FrontCover); picture.setDescription("description"); picture.setPicture("data"); values.append(ASF::Attribute(picture)); ASF::Picture picture2; picture2.setMimeType("image/png"); picture2.setType(ASF::Picture::BackCover); picture2.setDescription("back cover"); picture2.setPicture("PNG data"); values.append(ASF::Attribute(picture2)); f->tag()->attributeListMap()["WM/Picture"] = values; f->save(); delete f; f = new ASF::File(newname.c_str()); ASF::AttributeList values2 = f->tag()->attributeListMap()["WM/Picture"]; CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), values2.size()); ASF::Picture picture3 = values2[1].toPicture(); CPPUNIT_ASSERT(picture3.isValid()); CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture3.mimeType()); CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture3.type()); CPPUNIT_ASSERT_EQUAL(String("description"), picture3.description()); CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture3.picture()); ASF::Picture picture4 = values2[0].toPicture(); CPPUNIT_ASSERT(picture4.isValid()); CPPUNIT_ASSERT_EQUAL(String("image/png"), picture4.mimeType()); CPPUNIT_ASSERT_EQUAL(ASF::Picture::BackCover, picture4.type()); CPPUNIT_ASSERT_EQUAL(String("back cover"), picture4.description()); CPPUNIT_ASSERT_EQUAL(ByteVector("PNG data"), picture4.picture()); delete f; } void testProperties() { ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); PropertyMap tags = f.properties(); tags["TRACKNUMBER"] = StringList("2"); tags["DISCNUMBER"] = StringList("3"); tags["BPM"] = StringList("123"); tags["ARTIST"] = StringList("Foo Bar"); f.setProperties(tags); tags = f.properties(); CPPUNIT_ASSERT_EQUAL(String("Foo Bar"), f.tag()->artist()); CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]); CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/BeatsPerMinute")); CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/BeatsPerMinute"].size()); CPPUNIT_ASSERT_EQUAL(String("123"), f.tag()->attributeListMap()["WM/BeatsPerMinute"].front().toString()); CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]); CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/TrackNumber")); CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/TrackNumber"].size()); CPPUNIT_ASSERT_EQUAL(String("2"), f.tag()->attributeListMap()["WM/TrackNumber"].front().toString()); CPPUNIT_ASSERT_EQUAL(StringList("2"), tags["TRACKNUMBER"]); CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/PartOfSet")); CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/PartOfSet"].size()); CPPUNIT_ASSERT_EQUAL(String("3"), f.tag()->attributeListMap()["WM/PartOfSet"].front().toString()); CPPUNIT_ASSERT_EQUAL(StringList("3"), tags["DISCNUMBER"]); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestASF); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_bytevector.cpp��������������������������������������������������������������0000664�0000000�0000000�00000020744�12225024651�0020065�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include <tbytevector.h> #include <tbytevectorlist.h> #include <cppunit/extensions/HelperMacros.h> using namespace std; using namespace TagLib; class TestByteVector : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestByteVector); CPPUNIT_TEST(testByteVector); CPPUNIT_TEST(testFind1); CPPUNIT_TEST(testFind2); CPPUNIT_TEST(testRfind1); CPPUNIT_TEST(testRfind2); CPPUNIT_TEST(testToHex); CPPUNIT_TEST(testToUShort); CPPUNIT_TEST(testReplace); CPPUNIT_TEST_SUITE_END(); public: void testConversion(unsigned int i, unsigned char a, unsigned char b, unsigned char c, unsigned char d) { ByteVector v(4, 0); v[3] = a; v[2] = b; v[1] = c; v[0] = d; CPPUNIT_ASSERT(v.toUInt(false) == i); v[0] = a; v[1] = b; v[2] = c; v[3] = d; CPPUNIT_ASSERT(v.toUInt() == i); } void testByteVector() { ByteVector v("foobar"); CPPUNIT_ASSERT(v.find("ob") == 2); CPPUNIT_ASSERT(v.find('b') == 3); ByteVector n(4, 0); n[0] = 1; CPPUNIT_ASSERT(n.toUInt(true) == 16777216); CPPUNIT_ASSERT(n.toUInt(false) == 1); CPPUNIT_ASSERT(ByteVector::fromUInt(16777216, true) == n); CPPUNIT_ASSERT(ByteVector::fromUInt(1, false) == n); CPPUNIT_ASSERT(ByteVector::fromUInt(0xa0).toUInt() == 0xa0); testConversion(0x000000a0, 0x00, 0x00, 0x00, 0xa0); testConversion(0xd50bf072, 0xd5, 0x0b, 0xf0, 0x72); ByteVector intVector(2, 0); intVector[0] = char(0xfc); intVector[1] = char(0x00); CPPUNIT_ASSERT(intVector.toShort() == -1024); intVector[0] = char(0x04); intVector[1] = char(0x00); CPPUNIT_ASSERT(intVector.toShort() == 1024); CPPUNIT_ASSERT(ByteVector::fromLongLong(1).toLongLong() == 1); CPPUNIT_ASSERT(ByteVector::fromLongLong(0).toLongLong() == 0); CPPUNIT_ASSERT(ByteVector::fromLongLong(0xffffffffffffffffLL).toLongLong() == -1); CPPUNIT_ASSERT(ByteVector::fromLongLong(0xfffffffffffffffeLL).toLongLong() == -2); CPPUNIT_ASSERT(ByteVector::fromLongLong(1024).toLongLong() == 1024); ByteVector a1("foo"); a1.append("bar"); CPPUNIT_ASSERT(a1 == "foobar"); ByteVector a2("foo"); a2.append("b"); CPPUNIT_ASSERT(a2 == "foob"); ByteVector a3; a3.append("b"); CPPUNIT_ASSERT(a3 == "b"); ByteVector s1("foo"); CPPUNIT_ASSERT(ByteVectorList::split(s1, " ").size() == 1); ByteVector s2("f"); CPPUNIT_ASSERT(ByteVectorList::split(s2, " ").size() == 1); CPPUNIT_ASSERT(ByteVector().size() == 0); CPPUNIT_ASSERT(ByteVector("asdf").clear().size() == 0); CPPUNIT_ASSERT(ByteVector("asdf").clear() == ByteVector()); ByteVector i("blah blah"); ByteVector j("blah"); CPPUNIT_ASSERT(i.containsAt(j, 5, 0)); CPPUNIT_ASSERT(i.containsAt(j, 6, 1)); CPPUNIT_ASSERT(i.containsAt(j, 6, 1, 3)); } void testFind1() { CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO")); CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 0)); CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 1)); CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 2)); CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 3)); CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 4)); CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 5)); CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 6)); CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 7)); CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 8)); } void testFind2() { CPPUNIT_ASSERT_EQUAL(0, ByteVector("\x01", 1).find("\x01")); CPPUNIT_ASSERT_EQUAL(0, ByteVector("\x01\x02", 2).find("\x01\x02")); CPPUNIT_ASSERT_EQUAL(-1, ByteVector("\x01", 1).find("\x02")); CPPUNIT_ASSERT_EQUAL(-1, ByteVector("\x01\x02", 2).find("\x01\x03")); } void testRfind1() { CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 0)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 1)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 2)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 3)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 4)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 5)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 6)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 7)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 8)); CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS")); } void testRfind2() { ByteVector r0("**************"); ByteVector r1("OggS**********"); ByteVector r2("**********OggS"); ByteVector r3("OggS******OggS"); ByteVector r4("OggS*OggS*OggS"); CPPUNIT_ASSERT_EQUAL(-1, r0.find("OggS")); CPPUNIT_ASSERT_EQUAL(-1, r0.rfind("OggS")); CPPUNIT_ASSERT_EQUAL(0, r1.find("OggS")); CPPUNIT_ASSERT_EQUAL(0, r1.rfind("OggS")); CPPUNIT_ASSERT_EQUAL(10, r2.find("OggS")); CPPUNIT_ASSERT_EQUAL(10, r2.rfind("OggS")); CPPUNIT_ASSERT_EQUAL(0, r3.find("OggS")); CPPUNIT_ASSERT_EQUAL(10, r3.rfind("OggS")); CPPUNIT_ASSERT_EQUAL(10, r4.rfind("OggS")); CPPUNIT_ASSERT_EQUAL(10, r4.rfind("OggS", 0)); CPPUNIT_ASSERT_EQUAL(5, r4.rfind("OggS", 7)); CPPUNIT_ASSERT_EQUAL(10, r4.rfind("OggS", 12)); } void testToHex() { ByteVector v("\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f", 16); CPPUNIT_ASSERT_EQUAL(ByteVector("f0e1d2c3b4a5968778695a4b3c2d1e0f"), v.toHex()); } void testToUShort() { CPPUNIT_ASSERT_EQUAL((unsigned short)0xFFFF, ByteVector("\xff\xff", 2).toUShort()); CPPUNIT_ASSERT_EQUAL((unsigned short)0x0001, ByteVector("\x00\x01", 2).toUShort()); CPPUNIT_ASSERT_EQUAL((unsigned short)0x0100, ByteVector("\x00\x01", 2).toUShort(false)); CPPUNIT_ASSERT_EQUAL((unsigned short)0xFF01, ByteVector("\xFF\x01", 2).toUShort()); CPPUNIT_ASSERT_EQUAL((unsigned short)0x01FF, ByteVector("\xFF\x01", 2).toUShort(false)); } void testReplace() { { ByteVector a("abcdabf"); a.replace(ByteVector(""), ByteVector("<a>")); CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); } { ByteVector a("abcdabf"); a.replace(ByteVector("foobartoolong"), ByteVector("<a>")); CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); } { ByteVector a("abcdabf"); a.replace(ByteVector("xx"), ByteVector("yy")); CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); } { ByteVector a("abcdabf"); a.replace(ByteVector("a"), ByteVector("x")); CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a); } { ByteVector a("abcdabf"); a.replace(ByteVector("ab"), ByteVector("xy")); CPPUNIT_ASSERT_EQUAL(ByteVector("xycdxyf"), a); } { ByteVector a("abcdabf"); a.replace(ByteVector("a"), ByteVector("<a>")); CPPUNIT_ASSERT_EQUAL(ByteVector("<a>bcd<a>bf"), a); } { ByteVector a("abcdabf"); a.replace(ByteVector("ab"), ByteVector("x")); CPPUNIT_ASSERT_EQUAL(ByteVector("xcdxf"), a); } { ByteVector a("abcdabf"); a.replace(ByteVector("ab"), ByteVector()); CPPUNIT_ASSERT_EQUAL(ByteVector("cdf"), a); } } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVector); ����������������������������taglib-1.9.1/tests/test_bytevectorlist.cpp����������������������������������������������������������0000664�0000000�0000000�00000001611�12225024651�0020751�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <tbytevector.h> #include <tbytevectorlist.h> #include <cppunit/extensions/HelperMacros.h> using namespace std; using namespace TagLib; class TestByteVectorList : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestByteVectorList); CPPUNIT_TEST(testSplitSingleChar); CPPUNIT_TEST(testSplitSingleChar_2); CPPUNIT_TEST_SUITE_END(); public: void testSplitSingleChar() { ByteVector v("a b"); ByteVectorList l = ByteVectorList::split(v, " "); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size()); CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); CPPUNIT_ASSERT_EQUAL(ByteVector("b"), l[1]); } void testSplitSingleChar_2() { ByteVector v("a"); ByteVectorList l = ByteVectorList::split(v, " "); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), l.size()); CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVectorList); �����������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_bytevectorstream.cpp��������������������������������������������������������0000664�0000000�0000000�00000004641�12225024651�0021277�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <tbytevectorstream.h> #include <cppunit/extensions/HelperMacros.h> using namespace std; using namespace TagLib; class TestByteVectorStream : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestByteVectorStream); CPPUNIT_TEST(testInitialData); CPPUNIT_TEST(testWriteBlock); CPPUNIT_TEST(testWriteBlockResize); CPPUNIT_TEST(testReadBlock); CPPUNIT_TEST(testRemoveBlock); CPPUNIT_TEST(testInsert); CPPUNIT_TEST_SUITE_END(); public: void testInitialData() { ByteVector v("abcd"); ByteVectorStream stream(v); CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), *stream.data()); } void testWriteBlock() { ByteVector v("abcd"); ByteVectorStream stream(v); stream.seek(1); stream.writeBlock(ByteVector("xx")); CPPUNIT_ASSERT_EQUAL(ByteVector("axxd"), *stream.data()); } void testWriteBlockResize() { ByteVector v("abcd"); ByteVectorStream stream(v); stream.seek(3); stream.writeBlock(ByteVector("xx")); CPPUNIT_ASSERT_EQUAL(ByteVector("abcxx"), *stream.data()); stream.seek(5); stream.writeBlock(ByteVector("yy")); CPPUNIT_ASSERT_EQUAL(ByteVector("abcxxyy"), *stream.data()); } void testReadBlock() { ByteVector v("abcd"); ByteVectorStream stream(v); CPPUNIT_ASSERT_EQUAL(ByteVector("a"), stream.readBlock(1)); CPPUNIT_ASSERT_EQUAL(ByteVector("bc"), stream.readBlock(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("d"), stream.readBlock(3)); CPPUNIT_ASSERT_EQUAL(ByteVector::null, stream.readBlock(3)); } void testRemoveBlock() { ByteVector v("abcd"); ByteVectorStream stream(v); stream.removeBlock(1, 1); CPPUNIT_ASSERT_EQUAL(ByteVector("acd"), *stream.data()); stream.removeBlock(0, 2); CPPUNIT_ASSERT_EQUAL(ByteVector("d"), *stream.data()); stream.removeBlock(0, 2); CPPUNIT_ASSERT_EQUAL(ByteVector(""), *stream.data()); } void testInsert() { ByteVector v("abcd"); ByteVectorStream stream(v); stream.insert(ByteVector("xx"), 1, 1); CPPUNIT_ASSERT_EQUAL(ByteVector("axxcd"), *stream.data()); stream.insert(ByteVector("yy"), 0, 2); CPPUNIT_ASSERT_EQUAL(ByteVector("yyxcd"), *stream.data()); stream.insert(ByteVector("foa"), 3, 2); CPPUNIT_ASSERT_EQUAL(ByteVector("yyxfoa"), *stream.data()); stream.insert(ByteVector("123"), 3, 0); CPPUNIT_ASSERT_EQUAL(ByteVector("yyx123foa"), *stream.data()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVectorStream); �����������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_fileref.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000007550�12225024651�0017313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <fileref.h> #include <oggflacfile.h> #include <vorbisfile.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestFileRef : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestFileRef); CPPUNIT_TEST(testASF); CPPUNIT_TEST(testMusepack); CPPUNIT_TEST(testVorbis); CPPUNIT_TEST(testSpeex); CPPUNIT_TEST(testFLAC); CPPUNIT_TEST(testMP3); CPPUNIT_TEST(testOGA_FLAC); CPPUNIT_TEST(testOGA_Vorbis); CPPUNIT_TEST(testMP4_1); CPPUNIT_TEST(testMP4_2); CPPUNIT_TEST(testMP4_3); CPPUNIT_TEST(testTrueAudio); CPPUNIT_TEST(testAPE); CPPUNIT_TEST(testWav); CPPUNIT_TEST(testUnsupported); CPPUNIT_TEST_SUITE_END(); public: void fileRefSave(const string &filename, const string &ext) { ScopedFileCopy copy(filename, ext); string newname = copy.fileName(); FileRef *f = new FileRef(newname.c_str()); CPPUNIT_ASSERT(!f->isNull()); f->tag()->setArtist("test artist"); f->tag()->setTitle("test title"); f->tag()->setGenre("Test!"); f->tag()->setAlbum("albummmm"); f->tag()->setTrack(5); f->tag()->setYear(2020); f->save(); delete f; f = new FileRef(newname.c_str()); CPPUNIT_ASSERT(!f->isNull()); CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("test artist")); CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("test title")); CPPUNIT_ASSERT_EQUAL(f->tag()->genre(), String("Test!")); CPPUNIT_ASSERT_EQUAL(f->tag()->album(), String("albummmm")); CPPUNIT_ASSERT_EQUAL(f->tag()->track(), TagLib::uint(5)); CPPUNIT_ASSERT_EQUAL(f->tag()->year(), TagLib::uint(2020)); f->tag()->setArtist("ttest artist"); f->tag()->setTitle("ytest title"); f->tag()->setGenre("uTest!"); f->tag()->setAlbum("ialbummmm"); f->tag()->setTrack(7); f->tag()->setYear(2080); f->save(); delete f; f = new FileRef(newname.c_str()); CPPUNIT_ASSERT(!f->isNull()); CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("ttest artist")); CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("ytest title")); CPPUNIT_ASSERT_EQUAL(f->tag()->genre(), String("uTest!")); CPPUNIT_ASSERT_EQUAL(f->tag()->album(), String("ialbummmm")); CPPUNIT_ASSERT_EQUAL(f->tag()->track(), TagLib::uint(7)); CPPUNIT_ASSERT_EQUAL(f->tag()->year(), TagLib::uint(2080)); delete f; } void testMusepack() { fileRefSave("click", ".mpc"); } void testASF() { fileRefSave("silence-1", ".wma"); } void testVorbis() { fileRefSave("empty", ".ogg"); } void testSpeex() { fileRefSave("empty", ".spx"); } void testFLAC() { fileRefSave("no-tags", ".flac"); } void testMP3() { fileRefSave("xing", ".mp3"); } void testTrueAudio() { fileRefSave("empty", ".tta"); } void testMP4_1() { fileRefSave("has-tags", ".m4a"); } void testMP4_2() { fileRefSave("no-tags", ".m4a"); } void testMP4_3() { fileRefSave("no-tags", ".3g2"); } void testWav() { fileRefSave("empty", ".wav"); } void testOGA_FLAC() { FileRef *f = new FileRef(TEST_FILE_PATH_C("empty_flac.oga")); CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File *>(f->file()) == NULL); CPPUNIT_ASSERT(dynamic_cast<Ogg::FLAC::File *>(f->file()) != NULL); } void testOGA_Vorbis() { FileRef *f = new FileRef(TEST_FILE_PATH_C("empty_vorbis.oga")); CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File *>(f->file()) != NULL); CPPUNIT_ASSERT(dynamic_cast<Ogg::FLAC::File *>(f->file()) == NULL); } void testAPE() { fileRefSave("mac-399", ".ape"); } void testUnsupported() { FileRef f1(TEST_FILE_PATH_C("no-extension")); CPPUNIT_ASSERT(f1.isNull()); FileRef f2(TEST_FILE_PATH_C("unsupported-extension.xxx")); CPPUNIT_ASSERT(f2.isNull()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestFileRef); ��������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_flac.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000017347�12225024651�0016611�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <tpropertymap.h> #include <flacfile.h> #include <xiphcomment.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestFLAC : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestFLAC); CPPUNIT_TEST(testSignature); CPPUNIT_TEST(testMultipleCommentBlocks); CPPUNIT_TEST(testReadPicture); CPPUNIT_TEST(testAddPicture); CPPUNIT_TEST(testReplacePicture); CPPUNIT_TEST(testRemoveAllPictures); CPPUNIT_TEST(testRepeatedSave); CPPUNIT_TEST(testSaveMultipleValues); CPPUNIT_TEST(testDict); CPPUNIT_TEST(testInvalid); CPPUNIT_TEST_SUITE_END(); public: void testSignature() { FLAC::File f(TEST_FILE_PATH_C("no-tags.flac")); CPPUNIT_ASSERT_EQUAL(ByteVector("a1b141f766e9849ac3db1030a20a3c77"), f.audioProperties()->signature().toHex()); } void testMultipleCommentBlocks() { ScopedFileCopy copy("multiple-vc", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(String("Artist 1"), f->tag()->artist()); f->tag()->setArtist("The Artist"); f->save(); delete f; f = new FLAC::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); delete f; } void testReadPicture() { ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); List<FLAC::Picture *> lst = f->pictureList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); FLAC::Picture *pic = lst.front(); CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); CPPUNIT_ASSERT_EQUAL(1, pic->width()); CPPUNIT_ASSERT_EQUAL(1, pic->height()); CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); CPPUNIT_ASSERT_EQUAL(0, pic->numColors()); CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType()); CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic->data().size()); } void testAddPicture() { ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); List<FLAC::Picture *> lst = f->pictureList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); FLAC::Picture *newpic = new FLAC::Picture(); newpic->setType(FLAC::Picture::BackCover); newpic->setWidth(5); newpic->setHeight(6); newpic->setColorDepth(16); newpic->setNumColors(7); newpic->setMimeType("image/jpeg"); newpic->setDescription("new image"); newpic->setData("JPEG data"); f->addPicture(newpic); f->save(); f = new FLAC::File(newname.c_str()); lst = f->pictureList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), lst.size()); FLAC::Picture *pic = lst[0]; CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); CPPUNIT_ASSERT_EQUAL(1, pic->width()); CPPUNIT_ASSERT_EQUAL(1, pic->height()); CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); CPPUNIT_ASSERT_EQUAL(0, pic->numColors()); CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType()); CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic->data().size()); pic = lst[1]; CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); CPPUNIT_ASSERT_EQUAL(5, pic->width()); CPPUNIT_ASSERT_EQUAL(6, pic->height()); CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); } void testReplacePicture() { ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); List<FLAC::Picture *> lst = f->pictureList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); FLAC::Picture *newpic = new FLAC::Picture(); newpic->setType(FLAC::Picture::BackCover); newpic->setWidth(5); newpic->setHeight(6); newpic->setColorDepth(16); newpic->setNumColors(7); newpic->setMimeType("image/jpeg"); newpic->setDescription("new image"); newpic->setData("JPEG data"); f->removePictures(); f->addPicture(newpic); f->save(); f = new FLAC::File(newname.c_str()); lst = f->pictureList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); FLAC::Picture *pic = lst[0]; CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); CPPUNIT_ASSERT_EQUAL(5, pic->width()); CPPUNIT_ASSERT_EQUAL(6, pic->height()); CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); } void testRemoveAllPictures() { ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); List<FLAC::Picture *> lst = f->pictureList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); f->removePictures(); f->save(); f = new FLAC::File(newname.c_str()); lst = f->pictureList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), lst.size()); } void testRepeatedSave() { ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); Tag *tag = f->tag(); CPPUNIT_ASSERT_EQUAL(String("Silence"), tag->title()); tag->setTitle("NEW TITLE"); f->save(); CPPUNIT_ASSERT_EQUAL(String("NEW TITLE"), tag->title()); tag->setTitle("NEW TITLE 2"); f->save(); CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), tag->title()); f = new FLAC::File(newname.c_str()); tag = f->tag(); CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), tag->title()); } void testSaveMultipleValues() { ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); Ogg::XiphComment* c = f->xiphComment(true); c->addField("ARTIST", "artist 1", true); c->addField("ARTIST", "artist 2", false); f->save(); delete f; f = new FLAC::File(newname.c_str()); c = f->xiphComment(true); Ogg::FieldListMap m = c->fieldListMap(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), m["ARTIST"].size()); CPPUNIT_ASSERT_EQUAL(String("artist 1"), m["ARTIST"][0]); CPPUNIT_ASSERT_EQUAL(String("artist 2"), m["ARTIST"][1]); } void testDict() { // test unicode & multiple values with dict interface ScopedFileCopy copy("silence-44-s", ".flac"); string newname = copy.fileName(); FLAC::File *f = new FLAC::File(newname.c_str()); PropertyMap dict; dict["ARTIST"].append("artøst 1"); dict["ARTIST"].append("artöst 2"); f->setProperties(dict); f->save(); delete f; f = new FLAC::File(newname.c_str()); dict = f->properties(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), dict["ARTIST"].size()); CPPUNIT_ASSERT_EQUAL(String("artøst 1"), dict["ARTIST"][0]); CPPUNIT_ASSERT_EQUAL(String("artöst 2"), dict["ARTIST"][1]); } void testInvalid() { ScopedFileCopy copy("silence-44-s", ".flac"); PropertyMap map; map["HÄÖ"] = String("bla"); FLAC::File f(copy.fileName().c_str()); PropertyMap invalid = f.setProperties(map); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), invalid.size()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f.properties().size()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_flacpicture.cpp�������������������������������������������������������������0000664�0000000�0000000�00000007236�12225024651�0020201�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <flacfile.h> #include <flacmetadatablock.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestFLACPicture : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestFLACPicture); CPPUNIT_TEST(testParse); CPPUNIT_TEST(testPassThrough); CPPUNIT_TEST_SUITE_END(); public: void testParse() { const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; const char *pdata = reinterpret_cast<const char*>(data); FLAC::Picture pic(ByteVector(pdata, 199)); CPPUNIT_ASSERT_EQUAL(3, int(pic.type())); CPPUNIT_ASSERT_EQUAL(1, pic.width()); CPPUNIT_ASSERT_EQUAL(1, pic.height()); CPPUNIT_ASSERT_EQUAL(24, pic.colorDepth()); CPPUNIT_ASSERT_EQUAL(0, pic.numColors()); CPPUNIT_ASSERT_EQUAL(String("image/png"), pic.mimeType()); CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic.description()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic.data().size()); } void testPassThrough() { const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; const char *pdata = reinterpret_cast<const char*>(data); FLAC::Picture pic(ByteVector(pdata, 199)); CPPUNIT_ASSERT_EQUAL(ByteVector(pdata, 199), pic.render()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestFLACPicture); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_flacunknownmetadatablock.cpp������������������������������������������������0000664�0000000�0000000�00000001732�12225024651�0022734�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <flacunknownmetadatablock.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestFLACUnknownMetadataBlock : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestFLACUnknownMetadataBlock); CPPUNIT_TEST(testAccessors); CPPUNIT_TEST_SUITE_END(); public: void testAccessors() { ByteVector data("abc\x01", 4); FLAC::UnknownMetadataBlock block(42, data); CPPUNIT_ASSERT_EQUAL(42, block.code()); CPPUNIT_ASSERT_EQUAL(data, block.data()); CPPUNIT_ASSERT_EQUAL(data, block.render()); ByteVector data2("xxx", 3); block.setCode(13); block.setData(data2); CPPUNIT_ASSERT_EQUAL(13, block.code()); CPPUNIT_ASSERT_EQUAL(data2, block.data()); CPPUNIT_ASSERT_EQUAL(data2, block.render()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestFLACUnknownMetadataBlock); ��������������������������������������taglib-1.9.1/tests/test_id3v1.cpp�������������������������������������������������������������������0000664�0000000�0000000�00000001464�12225024651�0016623�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tstring.h> #include <mpegfile.h> #include <id3v1tag.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestID3v1 : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestID3v1); CPPUNIT_TEST(testStripWhiteSpace); CPPUNIT_TEST_SUITE_END(); public: void testStripWhiteSpace() { ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); { MPEG::File f(newname.c_str()); f.ID3v1Tag(true)->setArtist("Artist "); f.save(); } { MPEG::File f(newname.c_str()); CPPUNIT_ASSERT(f.ID3v1Tag(false)); CPPUNIT_ASSERT_EQUAL(String("Artist"), f.ID3v1Tag(false)->artist()); } } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v1); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_id3v2.cpp�������������������������������������������������������������������0000664�0000000�0000000�00000073402�12225024651�0016625�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H #include <config.h> #endif #include <string> #include <stdio.h> // so evil :( #define protected public #include <id3v2tag.h> #include <mpegfile.h> #include <id3v2frame.h> #undef protected #include <uniquefileidentifierframe.h> #include <textidentificationframe.h> #include <attachedpictureframe.h> #include <unsynchronizedlyricsframe.h> #include <generalencapsulatedobjectframe.h> #include <relativevolumeframe.h> #include <popularimeterframe.h> #include <urllinkframe.h> #include <ownershipframe.h> #include <unknownframe.h> #include <tdebug.h> #include <tpropertymap.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class PublicFrame : public ID3v2::Frame { public: PublicFrame() : ID3v2::Frame(ByteVector("XXXX\0\0\0\0\0\0", 10)) {} String readStringField(const ByteVector &data, String::Type encoding, int *positon = 0) { return ID3v2::Frame::readStringField(data, encoding, positon); } virtual String toString() const { return String::null; } virtual void parseFields(const ByteVector &) {} virtual ByteVector renderFields() const { return ByteVector::null; } }; class TestID3v2 : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestID3v2); CPPUNIT_TEST(testUnsynchDecode); CPPUNIT_TEST(testDowngradeUTF8ForID3v23); CPPUNIT_TEST(testUTF16BEDelimiter); CPPUNIT_TEST(testUTF16Delimiter); CPPUNIT_TEST(testReadStringField); CPPUNIT_TEST(testParseAPIC); CPPUNIT_TEST(testParseAPIC_UTF16_BOM); CPPUNIT_TEST(testParseAPICv22); CPPUNIT_TEST(testDontRender22); CPPUNIT_TEST(testParseGEOB); CPPUNIT_TEST(testPOPMtoString); CPPUNIT_TEST(testParsePOPM); CPPUNIT_TEST(testParsePOPMWithoutCounter); CPPUNIT_TEST(testRenderPOPM); CPPUNIT_TEST(testPOPMFromFile); CPPUNIT_TEST(testParseRelativeVolumeFrame); CPPUNIT_TEST(testParseUniqueFileIdentifierFrame); CPPUNIT_TEST(testParseEmptyUniqueFileIdentifierFrame); CPPUNIT_TEST(testBrokenFrame1); CPPUNIT_TEST(testItunes24FrameSize); CPPUNIT_TEST(testParseUrlLinkFrame); CPPUNIT_TEST(testRenderUrlLinkFrame); CPPUNIT_TEST(testParseUserUrlLinkFrame); CPPUNIT_TEST(testRenderUserUrlLinkFrame); CPPUNIT_TEST(testParseOwnershipFrame); CPPUNIT_TEST(testRenderOwnershipFrame); CPPUNIT_TEST(testSaveUTF16Comment); CPPUNIT_TEST(testUpdateGenre23_1); CPPUNIT_TEST(testUpdateGenre23_2); CPPUNIT_TEST(testUpdateGenre24); CPPUNIT_TEST(testUpdateDate22); CPPUNIT_TEST(testDowngradeTo23); // CPPUNIT_TEST(testUpdateFullDate22); TODO TYE+TDA should be upgraded to TDRC together CPPUNIT_TEST(testCompressedFrameWithBrokenLength); CPPUNIT_TEST(testW000); CPPUNIT_TEST(testPropertyInterface); CPPUNIT_TEST(testPropertyInterface2); CPPUNIT_TEST(testDeleteFrame); CPPUNIT_TEST(testSaveAndStripID3v1ShouldNotAddFrameFromID3v1ToId3v2); CPPUNIT_TEST_SUITE_END(); public: void testUnsynchDecode() { MPEG::File f(TEST_FILE_PATH_C("unsynch.id3"), false); CPPUNIT_ASSERT(f.tag()); CPPUNIT_ASSERT_EQUAL(String("My babe just cares for me"), f.tag()->title()); } void testDowngradeUTF8ForID3v23() { ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF8); StringList sl; sl.append("Foo"); f.setText(sl); f.header()->setVersion(3); ByteVector data = f.render(); CPPUNIT_ASSERT_EQUAL((unsigned int)(4+4+2+1+6+2), data.size()); ID3v2::TextIdentificationFrame f2(data); CPPUNIT_ASSERT_EQUAL(sl, f2.fieldList()); CPPUNIT_ASSERT_EQUAL(String::UTF16, f2.textEncoding()); } void testUTF16BEDelimiter() { ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF16BE); StringList sl; sl.append("Foo"); sl.append("Bar"); f.setText(sl); CPPUNIT_ASSERT_EQUAL((unsigned int)(4+4+2+1+6+2+6), f.render().size()); } void testUTF16Delimiter() { ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF16); StringList sl; sl.append("Foo"); sl.append("Bar"); f.setText(sl); CPPUNIT_ASSERT_EQUAL((unsigned int)(4+4+2+1+8+2+8), f.render().size()); } void testBrokenFrame1() { MPEG::File f(TEST_FILE_PATH_C("broken-tenc.id3"), false); CPPUNIT_ASSERT(f.tag()); CPPUNIT_ASSERT(!f.ID3v2Tag()->frameListMap().contains("TENC")); } void testReadStringField() { PublicFrame f; ByteVector data("abc\0", 4); String str = f.readStringField(data, String::Latin1); CPPUNIT_ASSERT_EQUAL(String("abc"), str); } // http://bugs.kde.org/show_bug.cgi?id=151078 void testParseAPIC() { ID3v2::AttachedPictureFrame f(ByteVector("APIC" "\x00\x00\x00\x07" "\x00\x00" "\x00" "m\x00" "\x01" "d\x00" "\x00", 17)); CPPUNIT_ASSERT_EQUAL(String("m"), f.mimeType()); CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FileIcon, f.type()); CPPUNIT_ASSERT_EQUAL(String("d"), f.description()); } void testParseAPIC_UTF16_BOM() { ID3v2::AttachedPictureFrame f(ByteVector( "\x41\x50\x49\x43\x00\x02\x0c\x59\x00\x00\x01\x69\x6d\x61\x67\x65" "\x2f\x6a\x70\x65\x67\x00\x00\xfe\xff\x00\x63\x00\x6f\x00\x76\x00" "\x65\x00\x72\x00\x2e\x00\x6a\x00\x70\x00\x67\x00\x00\xff\xd8\xff", 16 * 3)); CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), f.mimeType()); CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, f.type()); CPPUNIT_ASSERT_EQUAL(String("cover.jpg"), f.description()); CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\xd8\xff", 3), f.picture()); } void testParseAPICv22() { ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); ByteVector data = ByteVector("PIC" "\x00\x00\x08" "\x00" "JPG" "\x01" "d\x00" "\x00", 18); ID3v2::AttachedPictureFrame *frame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(factory->createFrame(data, TagLib::uint(2))); CPPUNIT_ASSERT(frame); CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), frame->mimeType()); CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FileIcon, frame->type()); CPPUNIT_ASSERT_EQUAL(String("d"), frame->description()); } void testDontRender22() { ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); ByteVector data = ByteVector("FOO" "\x00\x00\x08" "\x00" "JPG" "\x01" "d\x00" "\x00", 18); ID3v2::AttachedPictureFrame *frame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(factory->createFrame(data, TagLib::uint(2))); CPPUNIT_ASSERT(frame); ID3v2::Tag tag; tag.addFrame(frame); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1034), tag.render().size()); } // http://bugs.kde.org/show_bug.cgi?id=151078 void testParseGEOB() { ID3v2::GeneralEncapsulatedObjectFrame f(ByteVector("GEOB" "\x00\x00\x00\x08" "\x00\x00" "\x00" "m\x00" "f\x00" "d\x00" "\x00", 18)); CPPUNIT_ASSERT_EQUAL(String("m"), f.mimeType()); CPPUNIT_ASSERT_EQUAL(String("f"), f.fileName()); CPPUNIT_ASSERT_EQUAL(String("d"), f.description()); } void testParsePOPM() { ID3v2::PopularimeterFrame f(ByteVector("POPM" "\x00\x00\x00\x17" "\x00\x00" "email@example.com\x00" "\x02" "\x00\x00\x00\x03", 33)); CPPUNIT_ASSERT_EQUAL(String("email@example.com"), f.email()); CPPUNIT_ASSERT_EQUAL(2, f.rating()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f.counter()); } void testParsePOPMWithoutCounter() { ID3v2::PopularimeterFrame f(ByteVector("POPM" "\x00\x00\x00\x13" "\x00\x00" "email@example.com\x00" "\x02", 29)); CPPUNIT_ASSERT_EQUAL(String("email@example.com"), f.email()); CPPUNIT_ASSERT_EQUAL(2, f.rating()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f.counter()); } void testRenderPOPM() { ID3v2::PopularimeterFrame f; f.setEmail("email@example.com"); f.setRating(2); f.setCounter(3); CPPUNIT_ASSERT_EQUAL( ByteVector("POPM" "\x00\x00\x00\x17" "\x00\x00" "email@example.com\x00" "\x02" "\x00\x00\x00\x03", 33), f.render()); } void testPOPMtoString() { ID3v2::PopularimeterFrame f; f.setEmail("email@example.com"); f.setRating(2); f.setCounter(3); CPPUNIT_ASSERT_EQUAL( String("email@example.com rating=2 counter=3"), f.toString()); } void testPOPMFromFile() { ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); ID3v2::PopularimeterFrame *f = new ID3v2::PopularimeterFrame(); f->setEmail("email@example.com"); f->setRating(200); f->setCounter(3); MPEG::File foo(newname.c_str()); foo.ID3v2Tag()->addFrame(f); foo.save(); MPEG::File bar(newname.c_str()); CPPUNIT_ASSERT_EQUAL(String("email@example.com"), dynamic_cast<ID3v2::PopularimeterFrame *>(bar.ID3v2Tag()->frameList("POPM").front())->email()); CPPUNIT_ASSERT_EQUAL(200, dynamic_cast<ID3v2::PopularimeterFrame *>(bar.ID3v2Tag()->frameList("POPM").front())->rating()); } // http://bugs.kde.org/show_bug.cgi?id=150481 void testParseRelativeVolumeFrame() { ID3v2::RelativeVolumeFrame f( ByteVector("RVA2" // Frame ID "\x00\x00\x00\x0B" // Frame size "\x00\x00" // Frame flags "ident\x00" // Identification "\x02" // Type of channel "\x00\x0F" // Volume adjustment "\x08" // Bits representing peak "\x45", 21)); // Peak volume CPPUNIT_ASSERT_EQUAL(String("ident"), f.identification()); CPPUNIT_ASSERT_EQUAL(15.0f / 512.0f, f.volumeAdjustment(ID3v2::RelativeVolumeFrame::FrontRight)); CPPUNIT_ASSERT_EQUAL((uchar)8, f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).bitsRepresentingPeak); CPPUNIT_ASSERT_EQUAL(ByteVector("\x45"), f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).peakVolume); } void testParseUniqueFileIdentifierFrame() { ID3v2::UniqueFileIdentifierFrame f( ByteVector("UFID" // Frame ID "\x00\x00\x00\x09" // Frame size "\x00\x00" // Frame flags "owner\x00" // Owner identifier "\x00\x01\x02", 19)); // Identifier CPPUNIT_ASSERT_EQUAL(String("owner"), f.owner()); CPPUNIT_ASSERT_EQUAL(ByteVector("\x00\x01\x02", 3), f.identifier()); } void testParseEmptyUniqueFileIdentifierFrame() { ID3v2::UniqueFileIdentifierFrame f( ByteVector("UFID" // Frame ID "\x00\x00\x00\x01" // Frame size "\x00\x00" // Frame flags "\x00" // Owner identifier "", 11)); // Identifier CPPUNIT_ASSERT_EQUAL(String(), f.owner()); CPPUNIT_ASSERT_EQUAL(ByteVector(), f.identifier()); } void testParseUrlLinkFrame() { ID3v2::UrlLinkFrame f( ByteVector("WOAF" // Frame ID "\x00\x00\x00\x12" // Frame size "\x00\x00" // Frame flags "http://example.com", 28)); // URL CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); } void testRenderUrlLinkFrame() { ID3v2::UrlLinkFrame f("WOAF"); f.setUrl("http://example.com"); CPPUNIT_ASSERT_EQUAL( ByteVector("WOAF" // Frame ID "\x00\x00\x00\x12" // Frame size "\x00\x00" // Frame flags "http://example.com", 28), // URL f.render()); } void testParseUserUrlLinkFrame() { ID3v2::UserUrlLinkFrame f( ByteVector("WXXX" // Frame ID "\x00\x00\x00\x17" // Frame size "\x00\x00" // Frame flags "\x00" // Text encoding "foo\x00" // Description "http://example.com", 33)); // URL CPPUNIT_ASSERT_EQUAL(String("foo"), f.description()); CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); } void testRenderUserUrlLinkFrame() { ID3v2::UserUrlLinkFrame f; f.setDescription("foo"); f.setUrl("http://example.com"); CPPUNIT_ASSERT_EQUAL( ByteVector("WXXX" // Frame ID "\x00\x00\x00\x17" // Frame size "\x00\x00" // Frame flags "\x00" // Text encoding "foo\x00" // Description "http://example.com", 33), // URL f.render()); } void testParseOwnershipFrame() { ID3v2::OwnershipFrame f( ByteVector("OWNE" // Frame ID "\x00\x00\x00\x19" // Frame size "\x00\x00" // Frame flags "\x00" // Text encoding "GBP1.99\x00" // Price paid "20120905" // Date of purchase "Beatport", 35)); // Seller CPPUNIT_ASSERT_EQUAL(String("GBP1.99"), f.pricePaid()); CPPUNIT_ASSERT_EQUAL(String("20120905"), f.datePurchased()); CPPUNIT_ASSERT_EQUAL(String("Beatport"), f.seller()); } void testRenderOwnershipFrame() { ID3v2::OwnershipFrame f; f.setPricePaid("GBP1.99"); f.setDatePurchased("20120905"); f.setSeller("Beatport"); CPPUNIT_ASSERT_EQUAL( ByteVector("OWNE" // Frame ID "\x00\x00\x00\x19" // Frame size "\x00\x00" // Frame flags "\x00" // Text encoding "GBP1.99\x00" // Price paid "20120905" // Date of purchase "Beatport", 35), // URL f.render()); } void testItunes24FrameSize() { MPEG::File f(TEST_FILE_PATH_C("005411.id3"), false); CPPUNIT_ASSERT(f.tag()); CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("TIT2")); CPPUNIT_ASSERT_EQUAL(String("Sunshine Superman"), f.ID3v2Tag()->frameListMap()["TIT2"].front()->toString()); } void testSaveUTF16Comment() { String::Type defaultEncoding = ID3v2::FrameFactory::instance()->defaultTextEncoding(); ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); ID3v2::FrameFactory::instance()->setDefaultTextEncoding(String::UTF16); MPEG::File foo(newname.c_str()); foo.strip(); foo.tag()->setComment("Test comment!"); foo.save(); MPEG::File bar(newname.c_str()); CPPUNIT_ASSERT_EQUAL(String("Test comment!"), bar.tag()->comment()); ID3v2::FrameFactory::instance()->setDefaultTextEncoding(defaultEncoding); } void testUpdateGenre23_1() { // "Refinement" is the same as the ID3v1 genre - duplicate ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); ByteVector data = ByteVector("TCON" // Frame ID "\x00\x00\x00\x10" // Frame size "\x00\x00" // Frame flags "\x00" // Encoding "(22)Death Metal", 26); // Text ID3v2::TextIdentificationFrame *frame = static_cast<TagLib::ID3v2::TextIdentificationFrame*>(factory->createFrame(data, TagLib::uint(3))); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), frame->fieldList().size()); CPPUNIT_ASSERT_EQUAL(String("Death Metal"), frame->fieldList()[0]); ID3v2::Tag tag; tag.addFrame(frame); CPPUNIT_ASSERT_EQUAL(String("Death Metal"), tag.genre()); } void testUpdateGenre23_2() { // "Refinement" is different from the ID3v1 genre ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); ByteVector data = ByteVector("TCON" // Frame ID "\x00\x00\x00\x13" // Frame size "\x00\x00" // Frame flags "\x00" // Encoding "(4)Eurodisco", 23); // Text ID3v2::TextIdentificationFrame *frame = static_cast<TagLib::ID3v2::TextIdentificationFrame*>(factory->createFrame(data, TagLib::uint(3))); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), frame->fieldList().size()); CPPUNIT_ASSERT_EQUAL(String("4"), frame->fieldList()[0]); CPPUNIT_ASSERT_EQUAL(String("Eurodisco"), frame->fieldList()[1]); ID3v2::Tag tag; tag.addFrame(frame); CPPUNIT_ASSERT_EQUAL(String("Disco Eurodisco"), tag.genre()); } void testUpdateGenre24() { ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); ByteVector data = ByteVector("TCON" // Frame ID "\x00\x00\x00\x0D" // Frame size "\x00\x00" // Frame flags "\0" // Encoding "14\0Eurodisco", 23); // Text ID3v2::TextIdentificationFrame *frame = static_cast<TagLib::ID3v2::TextIdentificationFrame*>(factory->createFrame(data, TagLib::uint(4))); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), frame->fieldList().size()); CPPUNIT_ASSERT_EQUAL(String("14"), frame->fieldList()[0]); CPPUNIT_ASSERT_EQUAL(String("Eurodisco"), frame->fieldList()[1]); ID3v2::Tag tag; tag.addFrame(frame); CPPUNIT_ASSERT_EQUAL(String("R&B Eurodisco"), tag.genre()); } void testUpdateDate22() { MPEG::File f(TEST_FILE_PATH_C("id3v22-tda.mp3"), false); CPPUNIT_ASSERT(f.tag()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2010), f.tag()->year()); } void testUpdateFullDate22() { MPEG::File f(TEST_FILE_PATH_C("id3v22-tda.mp3"), false); CPPUNIT_ASSERT(f.tag()); CPPUNIT_ASSERT_EQUAL(String("2010-04-03"), f.ID3v2Tag()->frameListMap()["TDRC"].front()->toString()); } void testDowngradeTo23() { ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); ID3v2::TextIdentificationFrame *tf; MPEG::File foo(newname.c_str()); tf = new ID3v2::TextIdentificationFrame("TDOR", String::Latin1); tf->setText("2011-03-16"); foo.ID3v2Tag()->addFrame(tf); tf = new ID3v2::TextIdentificationFrame("TDRC", String::Latin1); tf->setText("2012-04-17T12:01"); foo.ID3v2Tag()->addFrame(tf); tf = new ID3v2::TextIdentificationFrame("TMCL", String::Latin1); tf->setText(StringList().append("Guitar").append("Artist 1").append("Drums").append("Artist 2")); foo.ID3v2Tag()->addFrame(tf); tf = new ID3v2::TextIdentificationFrame("TIPL", String::Latin1); tf->setText(StringList().append("Producer").append("Artist 3").append("Mastering").append("Artist 4")); foo.ID3v2Tag()->addFrame(tf); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDRL", String::Latin1)); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDTG", String::Latin1)); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TMOO", String::Latin1)); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TPRO", String::Latin1)); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOA", String::Latin1)); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOT", String::Latin1)); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSST", String::Latin1)); foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOP", String::Latin1)); foo.save(MPEG::File::AllTags, true, 3); MPEG::File bar(newname.c_str()); tf = static_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TDOR").front()); CPPUNIT_ASSERT(tf); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), tf->fieldList().size()); CPPUNIT_ASSERT_EQUAL(String("2011"), tf->fieldList().front()); tf = static_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TDRC").front()); CPPUNIT_ASSERT(tf); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), tf->fieldList().size()); CPPUNIT_ASSERT_EQUAL(String("2012"), tf->fieldList().front()); tf = dynamic_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TIPL").front()); CPPUNIT_ASSERT(tf); CPPUNIT_ASSERT_EQUAL(TagLib::uint(8), tf->fieldList().size()); CPPUNIT_ASSERT_EQUAL(String("Guitar"), tf->fieldList()[0]); CPPUNIT_ASSERT_EQUAL(String("Artist 1"), tf->fieldList()[1]); CPPUNIT_ASSERT_EQUAL(String("Drums"), tf->fieldList()[2]); CPPUNIT_ASSERT_EQUAL(String("Artist 2"), tf->fieldList()[3]); CPPUNIT_ASSERT_EQUAL(String("Producer"), tf->fieldList()[4]); CPPUNIT_ASSERT_EQUAL(String("Artist 3"), tf->fieldList()[5]); CPPUNIT_ASSERT_EQUAL(String("Mastering"), tf->fieldList()[6]); CPPUNIT_ASSERT_EQUAL(String("Artist 4"), tf->fieldList()[7]); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDRL")); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDTG")); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TMOO")); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TPRO")); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOA")); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOT")); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSST")); CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOP")); } void testCompressedFrameWithBrokenLength() { MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame.mp3"), false); CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("APIC")); #ifdef HAVE_ZLIB ID3v2::AttachedPictureFrame *frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front()); CPPUNIT_ASSERT(frame); CPPUNIT_ASSERT_EQUAL(String("image/bmp"), frame->mimeType()); CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, frame->type()); CPPUNIT_ASSERT_EQUAL(String(""), frame->description()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(86414), frame->picture().size()); #else // Skip the test if ZLIB is not installed. // The message "Compressed frames are currently not supported." will be displayed. ID3v2::UnknownFrame *frame = dynamic_cast<TagLib::ID3v2::UnknownFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front()); CPPUNIT_ASSERT(frame); #endif } void testW000() { MPEG::File f(TEST_FILE_PATH_C("w000.mp3"), false); CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("W000")); ID3v2::UrlLinkFrame *frame = dynamic_cast<TagLib::ID3v2::UrlLinkFrame*>(f.ID3v2Tag()->frameListMap()["W000"].front()); CPPUNIT_ASSERT(frame); CPPUNIT_ASSERT_EQUAL(String("lukas.lalinsky@example.com____"), frame->url()); } void testPropertyInterface() { ScopedFileCopy copy("rare_frames", ".mp3"); string newname = copy.fileName(); MPEG::File f(newname.c_str()); PropertyMap dict = f.ID3v2Tag(false)->properties(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(6), dict.size()); CPPUNIT_ASSERT(dict.contains("USERTEXTDESCRIPTION1")); CPPUNIT_ASSERT(dict.contains("QuodLibet::USERTEXTDESCRIPTION2")); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), dict["USERTEXTDESCRIPTION1"].size()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), dict["QuodLibet::USERTEXTDESCRIPTION2"].size()); CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["USERTEXTDESCRIPTION1"][0]); CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["USERTEXTDESCRIPTION1"][1]); CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["QuodLibet::USERTEXTDESCRIPTION2"][0]); CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["QuodLibet::USERTEXTDESCRIPTION2"][1]); CPPUNIT_ASSERT_EQUAL(String("Pop"), dict["GENRE"].front()); CPPUNIT_ASSERT_EQUAL(String("http://a.user.url"), dict["URL:USERURL"].front()); CPPUNIT_ASSERT_EQUAL(String("http://a.user.url/with/empty/description"), dict["URL"].front()); CPPUNIT_ASSERT_EQUAL(String("A COMMENT"), dict["COMMENT"].front()); CPPUNIT_ASSERT_EQUAL(1u, dict.unsupportedData().size()); CPPUNIT_ASSERT_EQUAL(String("UFID/supermihi@web.de"), dict.unsupportedData().front()); } void testPropertyInterface2() { ID3v2::Tag tag; ID3v2::UnsynchronizedLyricsFrame *frame1 = new ID3v2::UnsynchronizedLyricsFrame(); frame1->setDescription("test"); frame1->setText("la-la-la test"); tag.addFrame(frame1); ID3v2::UnsynchronizedLyricsFrame *frame2 = new ID3v2::UnsynchronizedLyricsFrame(); frame2->setDescription(""); frame2->setText("la-la-la nodescription"); tag.addFrame(frame2); ID3v2::AttachedPictureFrame *frame3 = new ID3v2::AttachedPictureFrame(); frame3->setDescription("test picture"); tag.addFrame(frame3); ID3v2::TextIdentificationFrame *frame4 = new ID3v2::TextIdentificationFrame("TIPL"); frame4->setText("single value is invalid for TIPL"); tag.addFrame(frame4); ID3v2::TextIdentificationFrame *frame5 = new ID3v2::TextIdentificationFrame("TMCL"); StringList tmclData; tmclData.append("VIOLIN"); tmclData.append("a violinist"); tmclData.append("PIANO"); tmclData.append("a pianist"); frame5->setText(tmclData); tag.addFrame(frame5); ID3v2::UniqueFileIdentifierFrame *frame6 = new ID3v2::UniqueFileIdentifierFrame("http://musicbrainz.org", "152454b9-19ba-49f3-9fc9-8fc26545cf41"); tag.addFrame(frame6); ID3v2::UniqueFileIdentifierFrame *frame7 = new ID3v2::UniqueFileIdentifierFrame("http://example.com", "123"); tag.addFrame(frame7); ID3v2::UserTextIdentificationFrame *frame8 = new ID3v2::UserTextIdentificationFrame(); frame8->setDescription("MusicBrainz Album Id"); frame8->setText("95c454a5-d7e0-4d8f-9900-db04aca98ab3"); tag.addFrame(frame8); PropertyMap properties = tag.properties(); CPPUNIT_ASSERT_EQUAL(3u, properties.unsupportedData().size()); CPPUNIT_ASSERT(properties.unsupportedData().contains("TIPL")); CPPUNIT_ASSERT(properties.unsupportedData().contains("APIC")); CPPUNIT_ASSERT(properties.unsupportedData().contains("UFID/http://example.com")); CPPUNIT_ASSERT(properties.contains("PERFORMER:VIOLIN")); CPPUNIT_ASSERT(properties.contains("PERFORMER:PIANO")); CPPUNIT_ASSERT_EQUAL(String("a violinist"), properties["PERFORMER:VIOLIN"].front()); CPPUNIT_ASSERT_EQUAL(String("a pianist"), properties["PERFORMER:PIANO"].front()); CPPUNIT_ASSERT(properties.contains("LYRICS")); CPPUNIT_ASSERT(properties.contains("LYRICS:TEST")); CPPUNIT_ASSERT(properties.contains("MUSICBRAINZ_TRACKID")); CPPUNIT_ASSERT_EQUAL(String("152454b9-19ba-49f3-9fc9-8fc26545cf41"), properties["MUSICBRAINZ_TRACKID"].front()); CPPUNIT_ASSERT(properties.contains("MUSICBRAINZ_ALBUMID")); CPPUNIT_ASSERT_EQUAL(String("95c454a5-d7e0-4d8f-9900-db04aca98ab3"), properties["MUSICBRAINZ_ALBUMID"].front()); tag.removeUnsupportedProperties(properties.unsupportedData()); CPPUNIT_ASSERT(tag.frameList("APIC").isEmpty()); CPPUNIT_ASSERT(tag.frameList("TIPL").isEmpty()); CPPUNIT_ASSERT_EQUAL((ID3v2::UniqueFileIdentifierFrame *)0, ID3v2::UniqueFileIdentifierFrame::findByOwner(&tag, "http://example.com")); CPPUNIT_ASSERT_EQUAL(frame6, ID3v2::UniqueFileIdentifierFrame::findByOwner(&tag, "http://musicbrainz.org")); } void testDeleteFrame() { ScopedFileCopy copy("rare_frames", ".mp3"); string newname = copy.fileName(); MPEG::File f(newname.c_str()); ID3v2::Tag *t = f.ID3v2Tag(); ID3v2::Frame *frame = t->frameList("TCON")[0]; CPPUNIT_ASSERT_EQUAL(1u, t->frameList("TCON").size()); t->removeFrame(frame, true); f.save(MPEG::File::ID3v2); MPEG::File f2(newname.c_str()); t = f2.ID3v2Tag(); CPPUNIT_ASSERT(t->frameList("TCON").isEmpty()); } void testSaveAndStripID3v1ShouldNotAddFrameFromID3v1ToId3v2() { ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); { MPEG::File foo(newname.c_str()); foo.tag()->setArtist("Artist"); foo.save(MPEG::File::ID3v1 | MPEG::File::ID3v2); } { MPEG::File bar(newname.c_str()); bar.ID3v2Tag()->removeFrames("TPE1"); // Should strip ID3v1 here and not add old values to ID3v2 again bar.save(MPEG::File::ID3v2, true); } MPEG::File f(newname.c_str()); CPPUNIT_ASSERT(!f.ID3v2Tag()->frameListMap().contains("TPE1")); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_info.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000002365�12225024651�0016631�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <infotag.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestInfoTag : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestInfoTag); CPPUNIT_TEST(testTitle); CPPUNIT_TEST(testNumericFields); CPPUNIT_TEST_SUITE_END(); public: void testTitle() { RIFF::Info::Tag tag; CPPUNIT_ASSERT_EQUAL(String(""), tag.title()); tag.setTitle("Test title 1"); tag.setFieldText("TEST", "Dummy Text"); CPPUNIT_ASSERT_EQUAL(String("Test title 1"), tag.title()); RIFF::Info::FieldListMap map = tag.fieldListMap(); CPPUNIT_ASSERT_EQUAL(String("Test title 1"), map["INAM"]); CPPUNIT_ASSERT_EQUAL(String("Dummy Text"), map["TEST"]); } void testNumericFields() { RIFF::Info::Tag tag; CPPUNIT_ASSERT_EQUAL((uint)0, tag.track()); tag.setTrack(1234); CPPUNIT_ASSERT_EQUAL((uint)1234, tag.track()); CPPUNIT_ASSERT_EQUAL(String("1234"), tag.fieldText("IPRT")); CPPUNIT_ASSERT_EQUAL((uint)0, tag.year()); tag.setYear(1234); CPPUNIT_ASSERT_EQUAL((uint)1234, tag.year()); CPPUNIT_ASSERT_EQUAL(String("1234"), tag.fieldText("ICRD")); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestInfoTag); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_it.cpp����������������������������������������������������������������������0000664�0000000�0000000�00000012175�12225024651�0016312�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include <itfile.h> #include <tstringlist.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; using TagLib::uint; static const String titleBefore("test song name"); static const String titleAfter("changed title"); static const String commentBefore( "This is a sample name.\n" "In module file formats\n" "sample names are abused\n" "as multiline comments.\n" " "); static const String newComment( "This is a sample name!\n" "In module file formats\n" "sample names are abused\n" "as multiline comments.\n" "-----------------------------------\n" "The previous line is truncated but starting with this line\n" "the comment is not limeted in the line length but to 8000\n" "additional characters (bytes).\n" "\n" "This is because it is saved in the 'message' proportion of\n" "IT files."); static const String commentAfter( "This is a sample name!\n" "In module file formats\n" "sample names are abused\n" "as multiline comments.\n" "-------------------------\n" "The previous line is truncated but starting with this line\n" "the comment is not limeted in the line length but to 8000\n" "additional characters (bytes).\n" "\n" "This is because it is saved in the 'message' proportion of\n" "IT files."); class TestIT : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestIT); CPPUNIT_TEST(testReadTags); CPPUNIT_TEST(testWriteTags); CPPUNIT_TEST_SUITE_END(); public: void testReadTags() { testRead(TEST_FILE_PATH_C("test.it"), titleBefore, commentBefore); } void testWriteTags() { ScopedFileCopy copy("test", ".it"); { IT::File file(copy.fileName().c_str()); CPPUNIT_ASSERT(file.tag() != 0); file.tag()->setTitle(titleAfter); file.tag()->setComment(newComment); file.tag()->setTrackerName("won't be saved"); CPPUNIT_ASSERT(file.save()); } testRead(copy.fileName().c_str(), titleAfter, commentAfter); } private: void testRead(FileName fileName, const String &title, const String &comment) { IT::File file(fileName); CPPUNIT_ASSERT(file.isValid()); IT::Properties *p = file.audioProperties(); Mod::Tag *t = file.tag(); CPPUNIT_ASSERT(0 != p); CPPUNIT_ASSERT(0 != t); CPPUNIT_ASSERT_EQUAL( 0, p->length()); CPPUNIT_ASSERT_EQUAL( 0, p->bitrate()); CPPUNIT_ASSERT_EQUAL( 0, p->sampleRate()); CPPUNIT_ASSERT_EQUAL(64, p->channels()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->lengthInPatterns()); CPPUNIT_ASSERT_EQUAL(true, p->stereo()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->instrumentCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 5, p->sampleCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)535, p->version()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)532, p->compatibleVersion()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 9, p->flags()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar)128, p->globalVolume()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 48, p->mixVolume()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar)125, p->tempo()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 6, p->bpmSpeed()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar)128, p->panningSeparation()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 0, p->pitchWheelDepth()); CPPUNIT_ASSERT_EQUAL(title, t->title()); CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); CPPUNIT_ASSERT_EQUAL(String::null, t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(String("Impulse Tracker"), t->trackerName()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestIT); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_list.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000003540�12225024651�0016645�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include <cppunit/extensions/HelperMacros.h> #include <tlist.h> using namespace std; using namespace TagLib; class TestList : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestList); CPPUNIT_TEST(testList); CPPUNIT_TEST_SUITE_END(); public: void testList() { List<int> l1; List<int> l2; List<int> l3; l1.append(2); l2.append(3); l2.append(4); l1.append(l2); l1.prepend(1); l3.append(1); l3.append(2); l3.append(3); l3.append(4); CPPUNIT_ASSERT(l1 == l3); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestList); ����������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_map.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000000763�12225024651�0016453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <tstring.h> #include <tmap.h> using namespace std; using namespace TagLib; class TestMap : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestMap); CPPUNIT_TEST(testInsert); CPPUNIT_TEST_SUITE_END(); public: void testInsert() { Map<String, int> m; m.insert("foo", 3); CPPUNIT_ASSERT_EQUAL(3, m["foo"]); m.insert("foo", 7); CPPUNIT_ASSERT_EQUAL(7, m["foo"]); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMap); �������������taglib-1.9.1/tests/test_mod.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000010654�12225024651�0016455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include <modfile.h> #include <tpropertymap.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; static const String titleBefore("title of song"); static const String titleAfter("changed title"); static const String commentBefore( "Instrument names\n" "are abused as\n" "comments in\n" "module file formats.\n" "-+-+-+-+-+-+-+-+-+-+-+\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); static const String newComment( "This line will be truncated because it is too long for a mod instrument name.\n" "This line is ok."); static const String commentAfter( "This line will be trun\n" "This line is ok.\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); class TestMod : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestMod); CPPUNIT_TEST(testReadTags); CPPUNIT_TEST(testWriteTags); CPPUNIT_TEST(testPropertyInterface); CPPUNIT_TEST_SUITE_END(); public: void testReadTags() { testRead(TEST_FILE_PATH_C("test.mod"), titleBefore, commentBefore); } void testWriteTags() { ScopedFileCopy copy("test", ".mod"); { Mod::File file(copy.fileName().c_str()); CPPUNIT_ASSERT(file.tag() != 0); file.tag()->setTitle(titleAfter); file.tag()->setComment(newComment); CPPUNIT_ASSERT(file.save()); } testRead(copy.fileName().c_str(), titleAfter, commentAfter); CPPUNIT_ASSERT(fileEqual( copy.fileName(), TEST_FILE_PATH_C("changed.mod"))); } void testPropertyInterface() { Mod::Tag t; PropertyMap properties; properties["BLA"] = String("bla"); properties["ARTIST"] = String("artist1"); properties["ARTIST"].append("artist2"); properties["TITLE"] = String("title"); PropertyMap unsupported = t.setProperties(properties); CPPUNIT_ASSERT(unsupported.contains("BLA")); CPPUNIT_ASSERT(unsupported.contains("ARTIST")); CPPUNIT_ASSERT_EQUAL(properties["ARTIST"], unsupported["ARTIST"]); CPPUNIT_ASSERT(!unsupported.contains("TITLE")); } private: void testRead(FileName fileName, const String &title, const String &comment) { Mod::File file(fileName); CPPUNIT_ASSERT(file.isValid()); Mod::Properties *p = file.audioProperties(); Mod::Tag *t = file.tag(); CPPUNIT_ASSERT(0 != p); CPPUNIT_ASSERT(0 != t); CPPUNIT_ASSERT_EQUAL(0, p->length()); CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); CPPUNIT_ASSERT_EQUAL(8, p->channels()); CPPUNIT_ASSERT_EQUAL(31U, p->instrumentCount()); CPPUNIT_ASSERT_EQUAL((uchar)1, p->lengthInPatterns()); CPPUNIT_ASSERT_EQUAL(title, t->title()); CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); CPPUNIT_ASSERT_EQUAL(String::null, t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(String("StarTrekker"), t->trackerName()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMod); ������������������������������������������������������������������������������������taglib-1.9.1/tests/test_mp4.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000023076�12225024651�0016400�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <mp4tag.h> #include <tbytevectorlist.h> #include <tpropertymap.h> #include <mp4atom.h> #include <mp4file.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestMP4 : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestMP4); CPPUNIT_TEST(testPropertiesAAC); CPPUNIT_TEST(testPropertiesALAC); CPPUNIT_TEST(testFreeForm); CPPUNIT_TEST(testCheckValid); CPPUNIT_TEST(testUpdateStco); CPPUNIT_TEST(testSaveExisingWhenIlstIsLast); CPPUNIT_TEST(test64BitAtom); CPPUNIT_TEST(testGnre); CPPUNIT_TEST(testCovrRead); CPPUNIT_TEST(testCovrWrite); CPPUNIT_TEST(testCovrRead2); CPPUNIT_TEST(testProperties); CPPUNIT_TEST_SUITE_END(); public: void testPropertiesAAC() { MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); CPPUNIT_ASSERT_EQUAL(16, ((MP4::Properties *)f.audioProperties())->bitsPerSample()); CPPUNIT_ASSERT_EQUAL(MP4::Properties::AAC, ((MP4::Properties *)f.audioProperties())->codec()); } void testPropertiesALAC() { MP4::File f(TEST_FILE_PATH_C("empty_alac.m4a")); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); CPPUNIT_ASSERT_EQUAL(16, ((MP4::Properties *)f.audioProperties())->bitsPerSample()); CPPUNIT_ASSERT_EQUAL(MP4::Properties::ALAC, ((MP4::Properties *)f.audioProperties())->codec()); } void testCheckValid() { MP4::File f(TEST_FILE_PATH_C("empty.aiff")); CPPUNIT_ASSERT(!f.isValid()); MP4::File f2(TEST_FILE_PATH_C("has-tags.m4a")); CPPUNIT_ASSERT(f2.isValid()); } void testUpdateStco() { ScopedFileCopy copy("no-tags", ".3g2"); string filename = copy.fileName(); MP4::File *f = new MP4::File(filename.c_str()); f->tag()->setArtist(ByteVector(3000, 'x')); ByteVectorList data1; { MP4::Atoms a(f); MP4::Atom *stco = a.find("moov")->findall("stco", true)[0]; f->seek(stco->offset + 12); ByteVector data = f->readBlock(stco->length - 12); unsigned int count = data.mid(0, 4).toUInt(); int pos = 4; while (count--) { unsigned int offset = data.mid(pos, 4).toUInt(); f->seek(offset); data1.append(f->readBlock(20)); pos += 4; } } f->save(); delete f; f = new MP4::File(filename.c_str()); { MP4::Atoms a(f); MP4::Atom *stco = a.find("moov")->findall("stco", true)[0]; f->seek(stco->offset + 12); ByteVector data = f->readBlock(stco->length - 12); unsigned int count = data.mid(0, 4).toUInt(); int pos = 4, i = 0; while (count--) { unsigned int offset = data.mid(pos, 4).toUInt(); f->seek(offset); CPPUNIT_ASSERT_EQUAL(data1[i], f->readBlock(20)); pos += 4; i++; } } delete f; } void testFreeForm() { ScopedFileCopy copy("has-tags", ".m4a"); string filename = copy.fileName(); MP4::File *f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:com.apple.iTunes:iTunNORM")); f->tag()->itemListMap()["----:org.kde.TagLib:Foo"] = StringList("Bar"); f->save(); delete f; f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:org.kde.TagLib:Foo")); CPPUNIT_ASSERT_EQUAL(String("Bar"), f->tag()->itemListMap()["----:org.kde.TagLib:Foo"].toStringList()[0]); f->save(); delete f; } void testSaveExisingWhenIlstIsLast() { ScopedFileCopy copy("ilst-is-last", ".m4a"); string filename = copy.fileName(); MP4::File *f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT_EQUAL(String("82,164"), f->tag()->itemListMap()["----:com.apple.iTunes:replaygain_track_minmax"].toStringList()[0]); CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f->tag()->artist()); f->tag()->setComment("foo"); f->save(); delete f; f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT_EQUAL(String("82,164"), f->tag()->itemListMap()["----:com.apple.iTunes:replaygain_track_minmax"].toStringList()[0]); CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f->tag()->artist()); CPPUNIT_ASSERT_EQUAL(String("foo"), f->tag()->comment()); } void test64BitAtom() { ScopedFileCopy copy("64bit", ".mp4"); string filename = copy.fileName(); MP4::File *f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool()); MP4::Atoms *atoms = new MP4::Atoms(f); MP4::Atom *moov = atoms->atoms[0]; CPPUNIT_ASSERT_EQUAL(long(77), moov->length); f->tag()->itemListMap()["pgap"] = true; f->save(); f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool()); CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["pgap"].toBool()); atoms = new MP4::Atoms(f); moov = atoms->atoms[0]; // original size + 'pgap' size + padding CPPUNIT_ASSERT_EQUAL(long(77 + 25 + 974), moov->length); } void testGnre() { MP4::File *f = new MP4::File(TEST_FILE_PATH_C("gnre.m4a")); CPPUNIT_ASSERT_EQUAL(TagLib::String("Ska"), f->tag()->genre()); delete f; } void testCovrRead() { MP4::File *f = new MP4::File(TEST_FILE_PATH_C("has-tags.m4a")); CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size()); delete f; } void testCovrWrite() { ScopedFileCopy copy("has-tags", ".m4a"); string filename = copy.fileName(); MP4::File *f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList(); l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); f->tag()->itemListMap()["covr"] = l; f->save(); delete f; f = new MP4::File(filename.c_str()); CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); l = f->tag()->itemListMap()["covr"].toCoverArtList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), l.size()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[2].format()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), l[2].data().size()); delete f; } void testCovrRead2() { MP4::File *f = new MP4::File(TEST_FILE_PATH_C("covr-junk.m4a")); CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size()); delete f; } void testProperties() { MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); PropertyMap tags = f.properties(); CPPUNIT_ASSERT_EQUAL(StringList("Test Artist"), tags["ARTIST"]); tags["TRACKNUMBER"] = StringList("2/4"); tags["DISCNUMBER"] = StringList("3/5"); tags["BPM"] = StringList("123"); tags["ARTIST"] = StringList("Foo Bar"); tags["COMPILATION"] = StringList("1"); f.setProperties(tags); tags = f.properties(); CPPUNIT_ASSERT(f.tag()->itemListMap().contains("trkn")); CPPUNIT_ASSERT_EQUAL(2, f.tag()->itemListMap()["trkn"].toIntPair().first); CPPUNIT_ASSERT_EQUAL(4, f.tag()->itemListMap()["trkn"].toIntPair().second); CPPUNIT_ASSERT_EQUAL(StringList("2/4"), tags["TRACKNUMBER"]); CPPUNIT_ASSERT(f.tag()->itemListMap().contains("disk")); CPPUNIT_ASSERT_EQUAL(3, f.tag()->itemListMap()["disk"].toIntPair().first); CPPUNIT_ASSERT_EQUAL(5, f.tag()->itemListMap()["disk"].toIntPair().second); CPPUNIT_ASSERT_EQUAL(StringList("3/5"), tags["DISCNUMBER"]); CPPUNIT_ASSERT(f.tag()->itemListMap().contains("tmpo")); CPPUNIT_ASSERT_EQUAL(123, f.tag()->itemListMap()["tmpo"].toInt()); CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]); CPPUNIT_ASSERT(f.tag()->itemListMap().contains("\251ART")); CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), f.tag()->itemListMap()["\251ART"].toStringList()); CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]); CPPUNIT_ASSERT(f.tag()->itemListMap().contains("cpil")); CPPUNIT_ASSERT_EQUAL(true, f.tag()->itemListMap()["cpil"].toBool()); CPPUNIT_ASSERT_EQUAL(StringList("1"), tags["COMPILATION"]); tags["COMPILATION"] = StringList("0"); f.setProperties(tags); tags = f.properties(); CPPUNIT_ASSERT(f.tag()->itemListMap().contains("cpil")); CPPUNIT_ASSERT_EQUAL(false, f.tag()->itemListMap()["cpil"].toBool()); CPPUNIT_ASSERT_EQUAL(StringList("0"), tags["COMPILATION"]); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_mp4coverart.cpp�������������������������������������������������������������0000664�0000000�0000000�00000002433�12225024651�0020140�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <mp4coverart.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestMP4CoverArt : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestMP4CoverArt); CPPUNIT_TEST(testSimple); CPPUNIT_TEST(testList); CPPUNIT_TEST_SUITE_END(); public: void testSimple() { MP4::CoverArt c(MP4::CoverArt::PNG, "foo"); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c.format()); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c.data()); MP4::CoverArt c2(c); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c2.format()); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c2.data()); MP4::CoverArt c3 = c; CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c3.format()); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c3.data()); } void testList() { MP4::CoverArtList l; l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar")); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4CoverArt); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_mp4item.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000001603�12225024651�0017247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <mp4coverart.h> #include <mp4item.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestMP4Item : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestMP4Item); CPPUNIT_TEST(testCoverArtList); CPPUNIT_TEST_SUITE_END(); public: void testCoverArtList() { MP4::CoverArtList l; l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar")); MP4::Item i(l); MP4::CoverArtList l2 = i.toCoverArtList(); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data()); CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4Item); �����������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_mpc.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000004152�12225024651�0016451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <mpcfile.h> #include "utils.h" using namespace std; using namespace TagLib; class TestMPC : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestMPC); CPPUNIT_TEST(testPropertiesSV8); CPPUNIT_TEST(testPropertiesSV7); CPPUNIT_TEST(testPropertiesSV5); CPPUNIT_TEST(testPropertiesSV4); CPPUNIT_TEST_SUITE_END(); public: void testPropertiesSV8() { MPC::File f(TEST_FILE_PATH_C("sv8_header.mpc")); CPPUNIT_ASSERT_EQUAL(8, f.audioProperties()->mpcVersion()); CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } void testPropertiesSV7() { MPC::File f(TEST_FILE_PATH_C("click.mpc")); CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->mpcVersion()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } void testPropertiesSV5() { MPC::File f(TEST_FILE_PATH_C("sv5_header.mpc")); CPPUNIT_ASSERT_EQUAL(5, f.audioProperties()->mpcVersion()); CPPUNIT_ASSERT_EQUAL(26, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } void testPropertiesSV4() { MPC::File f(TEST_FILE_PATH_C("sv4_header.mpc")); CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->mpcVersion()); CPPUNIT_ASSERT_EQUAL(26, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMPC); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_mpeg.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000004704�12225024651�0016625�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tstring.h> #include <mpegfile.h> #include <id3v2tag.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestMPEG : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestMPEG); CPPUNIT_TEST(testVersion2DurationWithXingHeader); CPPUNIT_TEST(testSaveID3v24); CPPUNIT_TEST(testSaveID3v24WrongParam); CPPUNIT_TEST(testSaveID3v23); CPPUNIT_TEST_SUITE_END(); public: void testVersion2DurationWithXingHeader() { MPEG::File f(TEST_FILE_PATH_C("mpeg2.mp3")); CPPUNIT_ASSERT_EQUAL(5387, f.audioProperties()->length()); } void testSaveID3v24() { ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); String xxx = ByteVector(254, 'X'); MPEG::File f(newname.c_str()); CPPUNIT_ASSERT_EQUAL(false, f.hasID3v2Tag()); f.tag()->setTitle(xxx); f.tag()->setArtist("Artist A"); f.save(MPEG::File::AllTags, true, 4); CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); MPEG::File f2(newname.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f2.ID3v2Tag()->header()->majorVersion()); CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); } void testSaveID3v24WrongParam() { ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); String xxx = ByteVector(254, 'X'); MPEG::File f(newname.c_str()); f.tag()->setTitle(xxx); f.tag()->setArtist("Artist A"); f.save(MPEG::File::AllTags, true, 8); MPEG::File f2(newname.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f2.ID3v2Tag()->header()->majorVersion()); CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); } void testSaveID3v23() { ScopedFileCopy copy("xing", ".mp3"); string newname = copy.fileName(); String xxx = ByteVector(254, 'X'); MPEG::File f(newname.c_str()); CPPUNIT_ASSERT_EQUAL(false, f.hasID3v2Tag()); f.tag()->setTitle(xxx); f.tag()->setArtist("Artist A"); f.save(MPEG::File::AllTags, true, 3); CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); MPEG::File f2(newname.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f2.ID3v2Tag()->header()->majorVersion()); CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestMPEG); ������������������������������������������������������������taglib-1.9.1/tests/test_ogg.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000005536�12225024651�0016455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <tpropertymap.h> #include <oggfile.h> #include <vorbisfile.h> #include <oggpageheader.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestOGG : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestOGG); CPPUNIT_TEST(testSimple); CPPUNIT_TEST(testSplitPackets); CPPUNIT_TEST(testDictInterface1); CPPUNIT_TEST(testDictInterface2); CPPUNIT_TEST_SUITE_END(); public: void testSimple() { ScopedFileCopy copy("empty", ".ogg"); string newname = copy.fileName(); Vorbis::File *f = new Vorbis::File(newname.c_str()); f->tag()->setArtist("The Artist"); f->save(); delete f; f = new Vorbis::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); delete f; } void testSplitPackets() { ScopedFileCopy copy("empty", ".ogg"); string newname = copy.fileName(); Vorbis::File *f = new Vorbis::File(newname.c_str()); f->tag()->addField("test", ByteVector(128 * 1024, 'x') + ByteVector(1, '\0')); f->save(); delete f; f = new Vorbis::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(19, f->lastPageHeader()->pageSequenceNumber()); delete f; } void testDictInterface1() { ScopedFileCopy copy("empty", ".ogg"); string newname = copy.fileName(); Vorbis::File *f = new Vorbis::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->tag()->properties().size()); PropertyMap newTags; StringList values("value 1"); values.append("value 2"); newTags["ARTIST"] = values; f->tag()->setProperties(newTags); PropertyMap map = f->tag()->properties(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), map.size()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), map["ARTIST"].size()); CPPUNIT_ASSERT_EQUAL(String("value 1"), map["ARTIST"][0]); delete f; } void testDictInterface2() { ScopedFileCopy copy("test", ".ogg"); string newname = copy.fileName(); Vorbis::File *f = new Vorbis::File(newname.c_str()); PropertyMap tags = f->tag()->properties(); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), tags["UNUSUALTAG"].size()); CPPUNIT_ASSERT_EQUAL(String("usual value"), tags["UNUSUALTAG"][0]); CPPUNIT_ASSERT_EQUAL(String("another value"), tags["UNUSUALTAG"][1]); CPPUNIT_ASSERT_EQUAL(String("öäüoΣø", String::UTF8), tags["UNICODETAG"][0]); tags["UNICODETAG"][0] = String("νεω ναλυε", String::UTF8); tags.erase("UNUSUALTAG"); f->tag()->setProperties(tags); CPPUNIT_ASSERT_EQUAL(String("νεω ναλυε", String::UTF8), f->tag()->properties()["UNICODETAG"][0]); CPPUNIT_ASSERT_EQUAL(false, f->tag()->properties().contains("UNUSUALTAG")); delete f; } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestOGG); ������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_oggflac.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000001656�12225024651�0017302�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tstringlist.h> #include <tbytevectorlist.h> #include <oggfile.h> #include <oggflacfile.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestOggFLAC : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestOggFLAC); CPPUNIT_TEST(testFramingBit); CPPUNIT_TEST_SUITE_END(); public: void testFramingBit() { ScopedFileCopy copy("empty_flac", ".oga"); string newname = copy.fileName(); Ogg::FLAC::File *f = new Ogg::FLAC::File(newname.c_str()); f->tag()->setArtist("The Artist"); f->save(); delete f; f = new Ogg::FLAC::File(newname.c_str()); CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); f->seek(0, File::End); int size = f->tell(); CPPUNIT_ASSERT_EQUAL(9134, size); delete f; } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestOggFLAC); ����������������������������������������������������������������������������������taglib-1.9.1/tests/test_opus.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000004046�12225024651�0016662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tbytevectorlist.h> #include <opusfile.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestOpus : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestOpus); CPPUNIT_TEST(testProperties); CPPUNIT_TEST(testReadComments); CPPUNIT_TEST(testWriteComments); CPPUNIT_TEST_SUITE_END(); public: void testProperties() { Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus")); CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->length()); CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate()); CPPUNIT_ASSERT_EQUAL(48000, ((Ogg::Opus::Properties *)f.audioProperties())->inputSampleRate()); } void testReadComments() { Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus")); CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f.tag()->fieldListMap()["ENCODER"]); CPPUNIT_ASSERT(f.tag()->fieldListMap().contains("TESTDESCRIPTION")); CPPUNIT_ASSERT(!f.tag()->fieldListMap().contains("ARTIST")); CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f.tag()->vendorID()); } void testWriteComments() { ScopedFileCopy copy("correctness_gain_silent_output", ".opus"); string filename = copy.fileName(); Ogg::Opus::File *f = new Ogg::Opus::File(filename.c_str()); f->tag()->setArtist("Your Tester"); f->save(); delete f; f = new Ogg::Opus::File(filename.c_str()); CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f->tag()->fieldListMap()["ENCODER"]); CPPUNIT_ASSERT(f->tag()->fieldListMap().contains("TESTDESCRIPTION")); CPPUNIT_ASSERT_EQUAL(StringList("Your Tester"), f->tag()->fieldListMap()["ARTIST"]); CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f->tag()->vendorID()); delete f; } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestOpus); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_propertymap.cpp�������������������������������������������������������������0000664�0000000�0000000�00000001457�12225024651�0020261�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <tpropertymap.h> class TestPropertyMap : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestPropertyMap); CPPUNIT_TEST(testInvalidKeys); CPPUNIT_TEST_SUITE_END(); public: void testInvalidKeys() { TagLib::PropertyMap map1; CPPUNIT_ASSERT(map1.isEmpty()); map1["ÄÖÜ"].append("test"); CPPUNIT_ASSERT_EQUAL(map1.size(), 1u); TagLib::PropertyMap map2; map2["ÄÖÜ"].append("test"); CPPUNIT_ASSERT(map1 == map2); CPPUNIT_ASSERT(map1.contains(map2)); map2["ARTIST"] = TagLib::String("Test Artist"); CPPUNIT_ASSERT(map1 != map2); CPPUNIT_ASSERT(map2.contains(map1)); map2["ÄÖÜ"].append("test 2"); CPPUNIT_ASSERT(!map2.contains(map1)); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestPropertyMap); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_riff.cpp��������������������������������������������������������������������0000664�0000000�0000000�00000020246�12225024651�0016622�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <tag.h> #include <tbytevectorlist.h> #include <rifffile.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class PublicRIFF : public RIFF::File { public: PublicRIFF(FileName file) : RIFF::File(file, BigEndian) {}; TagLib::uint riffSize() { return RIFF::File::riffSize(); }; TagLib::uint chunkCount() { return RIFF::File::chunkCount(); }; TagLib::uint chunkOffset(TagLib::uint i) { return RIFF::File::chunkOffset(i); }; TagLib::uint chunkPadding(TagLib::uint i) { return RIFF::File::chunkPadding(i); }; TagLib::uint chunkDataSize(TagLib::uint i) { return RIFF::File::chunkDataSize(i); }; ByteVector chunkName(TagLib::uint i) { return RIFF::File::chunkName(i); }; ByteVector chunkData(TagLib::uint i) { return RIFF::File::chunkData(i); }; void setChunkData(const ByteVector &name, const ByteVector &data) { RIFF::File::setChunkData(name, data); }; virtual TagLib::Tag* tag() const { return 0; }; virtual TagLib::AudioProperties* audioProperties() const { return 0;}; virtual bool save() { return false; }; }; class TestRIFF : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestRIFF); CPPUNIT_TEST(testPadding); CPPUNIT_TEST(testLastChunkAtEvenPosition); CPPUNIT_TEST(testLastChunkAtEvenPosition2); CPPUNIT_TEST(testLastChunkAtEvenPosition3); CPPUNIT_TEST_SUITE_END(); public: void testPadding() { ScopedFileCopy copy("empty", ".aiff"); string filename = copy.fileName(); PublicRIFF *f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0x1728 + 8), f->chunkOffset(2)); f->setChunkData("TEST", "foo"); delete f; f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0x1728 + 8), f->chunkOffset(2)); f->setChunkData("SSND", "abcd"); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(1)); CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->chunkData(1)); f->seek(f->chunkOffset(1)); CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->readBlock(4)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2)); f->seek(f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->readBlock(3)); delete f; f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(1)); CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->chunkData(1)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2)); } void testLastChunkAtEvenPosition() { ScopedFileCopy copy("noise", ".aif"); string filename = copy.fileName(); PublicRIFF *f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(long(4400), f->length()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize()); f->setChunkData("TEST", "abcd"); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4412 - 8), f->riffSize()); delete f; f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); CPPUNIT_ASSERT_EQUAL(long(4412), f->length()); delete f; } void testLastChunkAtEvenPosition2() { ScopedFileCopy copy("noise_odd", ".aif"); string filename = copy.fileName(); PublicRIFF *f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(long(4399), f->length()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize()); f->setChunkData("TEST", "abcd"); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4412 - 8), f->riffSize()); delete f; f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); CPPUNIT_ASSERT_EQUAL(long(4412), f->length()); delete f; } void testLastChunkAtEvenPosition3() { ScopedFileCopy copy("noise_odd", ".aif"); string filename = copy.fileName(); PublicRIFF *f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(long(4399), f->length()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize()); f->setChunkData("TEST", "abc"); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(3)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4411 - 8), f->riffSize()); delete f; f = new PublicRIFF(filename.c_str()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(3)); CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(3)); CPPUNIT_ASSERT_EQUAL(long(4412), f->length()); delete f; } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestRIFF); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_s3m.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000011103�12225024651�0016366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include <s3mfile.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; static const String titleBefore("test song name"); static const String titleAfter("changed title"); static const String commentBefore( "This is an instrument name.\n" "Module file formats\n" "abuse instrument names\n" "as multiline comments.\n" " "); static const String newComment( "This is an instrument name!\n" "Module file formats\n" "abuse instrument names\n" "as multiline comments.\n" "-----------------------------------\n" "This line will be dropped and the previous is truncated."); static const String commentAfter( "This is an instrument name!\n" "Module file formats\n" "abuse instrument names\n" "as multiline comments.\n" "---------------------------"); class TestS3M : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestS3M); CPPUNIT_TEST(testReadTags); CPPUNIT_TEST(testWriteTags); CPPUNIT_TEST_SUITE_END(); public: void testReadTags() { testRead(TEST_FILE_PATH_C("test.s3m"), titleBefore, commentBefore); } void testWriteTags() { ScopedFileCopy copy("test", ".s3m"); { S3M::File file(copy.fileName().c_str()); CPPUNIT_ASSERT(file.tag() != 0); file.tag()->setTitle(titleAfter); file.tag()->setComment(newComment); file.tag()->setTrackerName("won't be saved"); CPPUNIT_ASSERT(file.save()); } testRead(copy.fileName().c_str(), titleAfter, commentAfter); CPPUNIT_ASSERT(fileEqual( copy.fileName(), TEST_FILE_PATH_C("changed.s3m"))); } private: void testRead(FileName fileName, const String &title, const String &comment) { S3M::File file(fileName); CPPUNIT_ASSERT(file.isValid()); S3M::Properties *p = file.audioProperties(); Mod::Tag *t = file.tag(); CPPUNIT_ASSERT(0 != p); CPPUNIT_ASSERT(0 != t); CPPUNIT_ASSERT_EQUAL( 0, p->length()); CPPUNIT_ASSERT_EQUAL( 0, p->bitrate()); CPPUNIT_ASSERT_EQUAL( 0, p->sampleRate()); CPPUNIT_ASSERT_EQUAL(16, p->channels()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->lengthInPatterns()); CPPUNIT_ASSERT_EQUAL(false, p->stereo()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 5, p->sampleCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->flags()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)4896, p->trackerVersion()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 2, p->fileFormatVersion()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 64, p->globalVolume()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 48, p->masterVolume()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar)125, p->tempo()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 6, p->bpmSpeed()); CPPUNIT_ASSERT_EQUAL(title, t->title()); CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); CPPUNIT_ASSERT_EQUAL(String::null, t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(String("ScreamTracker III"), t->trackerName()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestS3M); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_string.cpp������������������������������������������������������������������0000664�0000000�0000000�00000017152�12225024651�0017204�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include <tstring.h> #include <string.h> #include <cppunit/extensions/HelperMacros.h> using namespace std; using namespace TagLib; class TestString : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestString); CPPUNIT_TEST(testString); CPPUNIT_TEST(testRfind); CPPUNIT_TEST(testUTF16Encode); CPPUNIT_TEST(testUTF16Decode); CPPUNIT_TEST(testUTF16DecodeInvalidBOM); CPPUNIT_TEST(testUTF16DecodeEmptyWithBOM); CPPUNIT_TEST(testAppendCharDetach); CPPUNIT_TEST(testAppendStringDetach); CPPUNIT_TEST(testToInt); CPPUNIT_TEST(testSubstr); CPPUNIT_TEST(testNewline); CPPUNIT_TEST_SUITE_END(); public: void testString() { String s = "taglib string"; ByteVector v = "taglib string"; CPPUNIT_ASSERT(v == s.data(String::Latin1)); char str[] = "taglib string"; CPPUNIT_ASSERT(strcmp(s.toCString(), str) == 0); String unicode("José Carlos", String::UTF8); CPPUNIT_ASSERT(strcmp(unicode.toCString(), "Jos\xe9 Carlos") == 0); String latin = "Jos\xe9 Carlos"; CPPUNIT_ASSERT(strcmp(latin.toCString(true), "José Carlos") == 0); String c; c = "1"; CPPUNIT_ASSERT(c == L"1"); c = L'\u4E00'; CPPUNIT_ASSERT(c == L"\u4E00"); String unicode2(unicode.to8Bit(true), String::UTF8); CPPUNIT_ASSERT(unicode == unicode2); String unicode3(L"\u65E5\u672C\u8A9E"); CPPUNIT_ASSERT(*(unicode3.toCWString() + 1) == L'\u672C'); CPPUNIT_ASSERT(strcmp(String::number(0).toCString(), "0") == 0); CPPUNIT_ASSERT(strcmp(String::number(12345678).toCString(), "12345678") == 0); CPPUNIT_ASSERT(strcmp(String::number(-12345678).toCString(), "-12345678") == 0); String n = "123"; CPPUNIT_ASSERT(n.toInt() == 123); n = "-123"; CPPUNIT_ASSERT(n.toInt() == -123); CPPUNIT_ASSERT(String("0").toInt() == 0); CPPUNIT_ASSERT(String("1").toInt() == 1); CPPUNIT_ASSERT(String(" foo ").stripWhiteSpace() == String("foo")); CPPUNIT_ASSERT(String("foo ").stripWhiteSpace() == String("foo")); CPPUNIT_ASSERT(String(" foo").stripWhiteSpace() == String("foo")); CPPUNIT_ASSERT(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0); CPPUNIT_ASSERT(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0); ByteVector utf16 = unicode.data(String::UTF16); // Check to make sure that the BOM is there and that the data size is correct CPPUNIT_ASSERT(utf16.size() == 2 + (unicode.size() * 2)); CPPUNIT_ASSERT(unicode == String(utf16, String::UTF16)); } void testUTF16Encode() { String a("foo"); ByteVector b("\0f\0o\0o", 6); ByteVector c("f\0o\0o\0", 6); ByteVector d("\377\376f\0o\0o\0", 8); CPPUNIT_ASSERT(a.data(String::UTF16BE) != a.data(String::UTF16LE)); CPPUNIT_ASSERT(b == a.data(String::UTF16BE)); CPPUNIT_ASSERT(c == a.data(String::UTF16LE)); CPPUNIT_ASSERT_EQUAL(d, a.data(String::UTF16)); } void testUTF16Decode() { String a("foo"); ByteVector b("\0f\0o\0o", 6); ByteVector c("f\0o\0o\0", 6); ByteVector d("\377\376f\0o\0o\0", 8); CPPUNIT_ASSERT_EQUAL(a, String(b, String::UTF16BE)); CPPUNIT_ASSERT_EQUAL(a, String(c, String::UTF16LE)); CPPUNIT_ASSERT_EQUAL(a, String(d, String::UTF16)); } // this test is expected to print "TagLib: String::prepare() - // Invalid UTF16 string." on the console 3 times void testUTF16DecodeInvalidBOM() { ByteVector b(" ", 1); ByteVector c(" ", 2); ByteVector d(" \0f\0o\0o", 8); CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16)); CPPUNIT_ASSERT_EQUAL(String(), String(c, String::UTF16)); CPPUNIT_ASSERT_EQUAL(String(), String(d, String::UTF16)); } void testUTF16DecodeEmptyWithBOM() { ByteVector a("\377\376", 2); ByteVector b("\376\377", 2); CPPUNIT_ASSERT_EQUAL(String(), String(a, String::UTF16)); CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16)); } void testAppendStringDetach() { String a("a"); String b = a; a += "b"; CPPUNIT_ASSERT_EQUAL(String("ab"), a); CPPUNIT_ASSERT_EQUAL(String("a"), b); } void testAppendCharDetach() { String a("a"); String b = a; a += 'b'; CPPUNIT_ASSERT_EQUAL(String("ab"), a); CPPUNIT_ASSERT_EQUAL(String("a"), b); } void testRfind() { CPPUNIT_ASSERT_EQUAL(-1, String("foo.bar").rfind(".", 0)); CPPUNIT_ASSERT_EQUAL(-1, String("foo.bar").rfind(".", 1)); CPPUNIT_ASSERT_EQUAL(-1, String("foo.bar").rfind(".", 2)); CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 3)); CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 4)); CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 5)); CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 6)); CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 7)); CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".")); } void testToInt() { bool ok; CPPUNIT_ASSERT_EQUAL(String("123").toInt(&ok), 123); CPPUNIT_ASSERT_EQUAL(ok, true); CPPUNIT_ASSERT_EQUAL(String("-123").toInt(&ok), -123); CPPUNIT_ASSERT_EQUAL(ok, true); CPPUNIT_ASSERT_EQUAL(String("abc").toInt(&ok), 0); CPPUNIT_ASSERT_EQUAL(ok, false); CPPUNIT_ASSERT_EQUAL(String("1x").toInt(&ok), 1); CPPUNIT_ASSERT_EQUAL(ok, false); CPPUNIT_ASSERT_EQUAL(String("").toInt(&ok), 0); CPPUNIT_ASSERT_EQUAL(ok, false); CPPUNIT_ASSERT_EQUAL(String("-").toInt(&ok), 0); CPPUNIT_ASSERT_EQUAL(ok, false); CPPUNIT_ASSERT_EQUAL(String("123").toInt(), 123); CPPUNIT_ASSERT_EQUAL(String("-123").toInt(), -123); CPPUNIT_ASSERT_EQUAL(String("123aa").toInt(), 123); CPPUNIT_ASSERT_EQUAL(String("-123aa").toInt(), -123); } void testSubstr() { CPPUNIT_ASSERT_EQUAL(String("01"), String("0123456").substr(0, 2)); CPPUNIT_ASSERT_EQUAL(String("12"), String("0123456").substr(1, 2)); CPPUNIT_ASSERT_EQUAL(String("123456"), String("0123456").substr(1, 200)); } void testNewline() { ByteVector cr("abc\x0dxyz", 7); ByteVector lf("abc\x0axyz", 7); ByteVector crlf("abc\x0d\x0axyz", 8); CPPUNIT_ASSERT_EQUAL(uint(7), String(cr).size()); CPPUNIT_ASSERT_EQUAL(uint(7), String(lf).size()); CPPUNIT_ASSERT_EQUAL(uint(8), String(crlf).size()); CPPUNIT_ASSERT_EQUAL(L'\x0d', String(cr)[3]); CPPUNIT_ASSERT_EQUAL(L'\x0a', String(lf)[3]); CPPUNIT_ASSERT_EQUAL(L'\x0d', String(crlf)[3]); CPPUNIT_ASSERT_EQUAL(L'\x0a', String(crlf)[4]); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestString); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_synchdata.cpp���������������������������������������������������������������0000664�0000000�0000000�00000006513�12225024651�0017653�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #include <id3v2synchdata.h> #include <cppunit/extensions/HelperMacros.h> using namespace std; using namespace TagLib; class TestID3v2SynchData : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestID3v2SynchData); CPPUNIT_TEST(test1); CPPUNIT_TEST(test2); CPPUNIT_TEST(test3); CPPUNIT_TEST(testToUIntBroken); CPPUNIT_TEST(testToUIntBrokenAndTooLarge); CPPUNIT_TEST(testDecode1); CPPUNIT_TEST(testDecode2); CPPUNIT_TEST_SUITE_END(); public: void test1() { char data[] = { 0, 0, 0, 127 }; ByteVector v(data, 4); CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), TagLib::uint(127)); CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(127), v); } void test2() { char data[] = { 0, 0, 1, 0 }; ByteVector v(data, 4); CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), TagLib::uint(128)); CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(128), v); } void test3() { char data[] = { 0, 0, 1, 1 }; ByteVector v(data, 4); CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), TagLib::uint(129)); CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(129), v); } void testToUIntBroken() { char data[] = { 0, 0, 0, -1 }; char data2[] = { 0, 0, -1, -1 }; CPPUNIT_ASSERT_EQUAL(TagLib::uint(255), ID3v2::SynchData::toUInt(ByteVector(data, 4))); CPPUNIT_ASSERT_EQUAL(TagLib::uint(65535), ID3v2::SynchData::toUInt(ByteVector(data2, 4))); } void testToUIntBrokenAndTooLarge() { char data[] = { 0, 0, 0, -1, 0 }; ByteVector v(data, 5); CPPUNIT_ASSERT_EQUAL(TagLib::uint(255), ID3v2::SynchData::toUInt(v)); } void testDecode1() { ByteVector a("\xff\x00\x00", 3); a = ID3v2::SynchData::decode(a); CPPUNIT_ASSERT_EQUAL((unsigned int)2, a.size()); CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\x00", 2), a); } void testDecode2() { ByteVector a("\xff\x44", 2); a = ID3v2::SynchData::decode(a); CPPUNIT_ASSERT_EQUAL((unsigned int)2, a.size()); CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\x44", 2), a); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2SynchData); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_trueaudio.cpp���������������������������������������������������������������0000664�0000000�0000000�00000001136�12225024651�0017672�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <string> #include <stdio.h> #include <trueaudiofile.h> #include "utils.h" using namespace std; using namespace TagLib; class TestTrueAudio : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestTrueAudio); CPPUNIT_TEST(testReadPropertiesWithoutID3v2); CPPUNIT_TEST_SUITE_END(); public: void testReadPropertiesWithoutID3v2() { TrueAudio::File f(TEST_FILE_PATH_C("empty.tta")); CPPUNIT_ASSERT(f.audioProperties()); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestTrueAudio); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_wav.cpp���������������������������������������������������������������������0000664�0000000�0000000�00000001415�12225024651�0016466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <string> #include <stdio.h> #include <tag.h> #include <tbytevectorlist.h> #include <wavfile.h> #include "utils.h" using namespace std; using namespace TagLib; class TestWAV : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestWAV); CPPUNIT_TEST(testLength); CPPUNIT_TEST(testZeroSizeDataChunk); CPPUNIT_TEST_SUITE_END(); public: void testLength() { RIFF::WAV::File f(TEST_FILE_PATH_C("empty.wav")); CPPUNIT_ASSERT_EQUAL(true, f.isValid()); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); } void testZeroSizeDataChunk() { RIFF::WAV::File f(TEST_FILE_PATH_C("zero-size-chunk.wav")); CPPUNIT_ASSERT_EQUAL(false, f.isValid()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_wavpack.cpp�����������������������������������������������������������������0000664�0000000�0000000�00000001720�12225024651�0017324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cppunit/extensions/HelperMacros.h> #include <string> #include <stdio.h> #include <tag.h> #include <tbytevectorlist.h> #include <wavpackfile.h> #include "utils.h" using namespace std; using namespace TagLib; class TestWavPack : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestWavPack); CPPUNIT_TEST(testBasic); CPPUNIT_TEST(testLengthScan); CPPUNIT_TEST_SUITE_END(); public: void testBasic() { WavPack::File f(TEST_FILE_PATH_C("no_length.wv")); WavPack::Properties *props = f.audioProperties(); CPPUNIT_ASSERT_EQUAL(44100, props->sampleRate()); CPPUNIT_ASSERT_EQUAL(2, props->channels()); CPPUNIT_ASSERT_EQUAL(1, props->bitrate()); CPPUNIT_ASSERT_EQUAL(0x407, props->version()); } void testLengthScan() { WavPack::File f(TEST_FILE_PATH_C("no_length.wv")); WavPack::Properties *props = f.audioProperties(); CPPUNIT_ASSERT_EQUAL(4, props->length()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestWavPack); ������������������������������������������������taglib-1.9.1/tests/test_xiphcomment.cpp�������������������������������������������������������������0000664�0000000�0000000�00000004112�12225024651�0020221�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <stdio.h> #include <xiphcomment.h> #include <tpropertymap.h> #include <tdebug.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; class TestXiphComment : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestXiphComment); CPPUNIT_TEST(testYear); CPPUNIT_TEST(testSetYear); CPPUNIT_TEST(testTrack); CPPUNIT_TEST(testSetTrack); CPPUNIT_TEST(testInvalidKeys); CPPUNIT_TEST_SUITE_END(); public: void testYear() { Ogg::XiphComment cmt; CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), cmt.year()); cmt.addField("YEAR", "2009"); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2009), cmt.year()); cmt.addField("DATE", "2008"); CPPUNIT_ASSERT_EQUAL(TagLib::uint(2008), cmt.year()); } void testSetYear() { Ogg::XiphComment cmt; cmt.addField("YEAR", "2009"); cmt.addField("DATE", "2008"); cmt.setYear(1995); CPPUNIT_ASSERT(cmt.fieldListMap()["YEAR"].isEmpty()); CPPUNIT_ASSERT_EQUAL(String("1995"), cmt.fieldListMap()["DATE"].front()); } void testTrack() { Ogg::XiphComment cmt; CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), cmt.track()); cmt.addField("TRACKNUM", "7"); CPPUNIT_ASSERT_EQUAL(TagLib::uint(7), cmt.track()); cmt.addField("TRACKNUMBER", "8"); CPPUNIT_ASSERT_EQUAL(TagLib::uint(8), cmt.track()); } void testSetTrack() { Ogg::XiphComment cmt; cmt.addField("TRACKNUM", "7"); cmt.addField("TRACKNUMBER", "8"); cmt.setTrack(3); CPPUNIT_ASSERT(cmt.fieldListMap()["TRACKNUM"].isEmpty()); CPPUNIT_ASSERT_EQUAL(String("3"), cmt.fieldListMap()["TRACKNUMBER"].front()); } void testInvalidKeys() { PropertyMap map; map[""] = String("invalid key: empty string"); map["A=B"] = String("invalid key: contains '='"); map["A~B"] = String("invalid key: contains '~'"); Ogg::XiphComment cmt; PropertyMap unsuccessful = cmt.setProperties(map); CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), unsuccessful.size()); CPPUNIT_ASSERT(cmt.properties().isEmpty()); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestXiphComment); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/test_xm.cpp����������������������������������������������������������������������0000664�0000000�0000000�00000017036�12225024651�0016323�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** copyright : (C) 2011 by Mathias Panzenböck email : grosser.meister.morti@gmx.net ***************************************************************************/ /*************************************************************************** * 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., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ #include <xmfile.h> #include <cppunit/extensions/HelperMacros.h> #include "utils.h" using namespace std; using namespace TagLib; static const String titleBefore("title of song"); static const String titleAfter("changed title"); static const String trackerNameBefore("MilkyTracker "); static const String trackerNameAfter("TagLib"); static const String commentBefore( "Instrument names\n" "are abused as\n" "comments in\n" "module file formats.\n" "-+-+-+-+-+-+-+-+-+-+-+\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n" "Sample\n" "names\n" "are sometimes\n" "also abused as\n" "comments."); static const String newCommentShort( "Instrument names\n" "are abused as\n" "comments in\n" "module file formats.\n" "======================\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n" "Sample names\n" "are sometimes\n" "also abused as\n" "comments."); static const String newCommentLong( "Instrument names\n" "are abused as\n" "comments in\n" "module file formats.\n" "======================\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n" "Sample names\n" "are sometimes\n" "also abused as\n" "comments.\n" "\n\n\n\n\n\n\n" "TEST"); static const String commentAfter( "Instrument names\n" "are abused as\n" "comments in\n" "module file formats.\n" "======================\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n" "Sample names\n" "are sometimes\n" "also abused as\n" "comments.\n"); class TestXM : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestXM); CPPUNIT_TEST(testReadTags); CPPUNIT_TEST(testReadStrippedTags); CPPUNIT_TEST(testWriteTagsShort); CPPUNIT_TEST(testWriteTagsLong); CPPUNIT_TEST_SUITE_END(); public: void testReadTags() { testRead(TEST_FILE_PATH_C("test.xm"), titleBefore, commentBefore, trackerNameBefore); } void testReadStrippedTags() { XM::File file(TEST_FILE_PATH_C("stripped.xm")); CPPUNIT_ASSERT(file.isValid()); XM::Properties *p = file.audioProperties(); Mod::Tag *t = file.tag(); CPPUNIT_ASSERT(0 != p); CPPUNIT_ASSERT(0 != t); CPPUNIT_ASSERT_EQUAL(0, p->length()); CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); CPPUNIT_ASSERT_EQUAL(8, p->channels()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->lengthInPatterns()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->version()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0 , p->restartPosition()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->instrumentCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->flags()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 6, p->tempo()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)125, p->bpmSpeed()); CPPUNIT_ASSERT_EQUAL(titleBefore, t->title()); CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); CPPUNIT_ASSERT_EQUAL(String::null, t->album()); CPPUNIT_ASSERT_EQUAL(String::null, t->comment()); CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(String::null, t->trackerName()); } void testWriteTagsShort() { testWriteTags(newCommentShort); } void testWriteTagsLong() { testWriteTags(newCommentLong); } private: void testRead(FileName fileName, const String &title, const String &comment, const String &trackerName) { XM::File file(fileName); CPPUNIT_ASSERT(file.isValid()); XM::Properties *p = file.audioProperties(); Mod::Tag *t = file.tag(); CPPUNIT_ASSERT(0 != p); CPPUNIT_ASSERT(0 != t); CPPUNIT_ASSERT_EQUAL(0, p->length()); CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); CPPUNIT_ASSERT_EQUAL(8, p->channels()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->lengthInPatterns()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)260, p->version()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->restartPosition()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)128, p->instrumentCount()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->flags()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 6, p->tempo()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)125, p->bpmSpeed()); CPPUNIT_ASSERT_EQUAL(title, t->title()); CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); CPPUNIT_ASSERT_EQUAL(String::null, t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(trackerName, t->trackerName()); } void testWriteTags(const String &comment) { ScopedFileCopy copy("test", ".xm"); { XM::File file(copy.fileName().c_str()); CPPUNIT_ASSERT(file.tag() != 0); file.tag()->setTitle(titleAfter); file.tag()->setComment(comment); file.tag()->setTrackerName(trackerNameAfter); CPPUNIT_ASSERT(file.save()); } testRead(copy.fileName().c_str(), titleAfter, commentAfter, trackerNameAfter); CPPUNIT_ASSERT(fileEqual( copy.fileName(), TEST_FILE_PATH_C("changed.xm"))); } }; CPPUNIT_TEST_SUITE_REGISTRATION(TestXM); ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������taglib-1.9.1/tests/utils.h��������������������������������������������������������������������������0000664�0000000�0000000�00000004236�12225024651�0015443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H #include <config.h> #endif #ifdef _WIN32 #include <windows.h> #else #include <unistd.h> #include <fcntl.h> #include <sys/fcntl.h> #include <sys/stat.h> #endif #include <stdio.h> #include <string.h> #include <string> #include <fstream> using namespace std; inline string testFilePath(const string &filename) { return string(TESTS_DIR "data/") + filename; } #define TEST_FILE_PATH_C(f) testFilePath(f).c_str() inline string copyFile(const string &filename, const string &ext) { string newname = string(tempnam(NULL, NULL)) + ext; string oldname = testFilePath(filename) + ext; #ifdef _WIN32 CopyFile(oldname.c_str(), newname.c_str(), FALSE); SetFileAttributes(newname.c_str(), GetFileAttributes(newname.c_str()) & ~FILE_ATTRIBUTE_READONLY); #else char buffer[4096]; int bytes; int inf = open(oldname.c_str(), O_RDONLY); int outf = open(newname.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); while((bytes = read(inf, buffer, sizeof(buffer))) > 0) write(outf, buffer, bytes); close(outf); close(inf); #endif return newname; } inline void deleteFile(const string &filename) { remove(filename.c_str()); } inline bool fileEqual(const string &filename1, const string &filename2) { char buf1[BUFSIZ]; char buf2[BUFSIZ]; ifstream stream1(filename1.c_str(), ios_base::in | ios_base::binary); ifstream stream2(filename2.c_str(), ios_base::in | ios_base::binary); if(!stream1 && !stream2) return true; if(!stream1 || !stream2) return false; for(;;) { stream1.read(buf1, BUFSIZ); stream2.read(buf2, BUFSIZ); streamsize n1 = stream1.gcount(); streamsize n2 = stream2.gcount(); if(n1 != n2) return false; if(n1 == 0) break; if(memcmp(buf1, buf2, n1) != 0) return false; } return stream1.good() == stream2.good(); } class ScopedFileCopy { public: ScopedFileCopy(const string &filename, const string &ext, bool deleteFile=true) { m_deleteFile = deleteFile; m_filename = copyFile(filename, ext); } ~ScopedFileCopy() { if(m_deleteFile) deleteFile(m_filename); } string fileName() { return m_filename; } private: bool m_deleteFile; string m_filename; }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������