Stupid Mercurial
This commit is contained in:
parent
97e94c0330
commit
28e55334a6
135 changed files with 33989 additions and 0 deletions
BIN
Frameworks/TagLib/English.lproj/InfoPlist.strings
Normal file
BIN
Frameworks/TagLib/English.lproj/InfoPlist.strings
Normal file
Binary file not shown.
26
Frameworks/TagLib/Info.plist
Normal file
26
Frameworks/TagLib/Info.plist
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.yourcompany.yourcocoaframework</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
11
Frameworks/TagLib/taglib/AUTHORS
Normal file
11
Frameworks/TagLib/taglib/AUTHORS
Normal file
|
@ -0,0 +1,11 @@
|
|||
Scott Wheeler <wheeler@kde.org>
|
||||
Author, maintainer
|
||||
Ismael Orenstein <orenstein@kde.org>
|
||||
Xing header implementation
|
||||
Allan Sandfeld Jensen <kde@carewolf.org>
|
||||
FLAC metadata implementation
|
||||
Teemu Tervo <teemu.tervo@gmx.net>
|
||||
Numerous bug reports and fixes
|
||||
|
||||
Please send all patches and questions to taglib-devel@kde.org rather than to
|
||||
individual developers!
|
502
Frameworks/TagLib/taglib/COPYING.LGPL
Normal file
502
Frameworks/TagLib/taglib/COPYING.LGPL
Normal file
|
@ -0,0 +1,502 @@
|
|||
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.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 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.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
11
Frameworks/TagLib/taglib/config.h
Normal file
11
Frameworks/TagLib/taglib/config.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* config-taglib.h. Generated by cmake from config-taglib.h.cmake */
|
||||
|
||||
/* NOTE: only add something here if it is really needed by all of kdelibs.
|
||||
Otherwise please prefer adding to the relevant config-foo.h.cmake file,
|
||||
to minimize recompilations and increase modularity. */
|
||||
/* Define if you have libz */
|
||||
#define HAVE_ZLIB 1
|
||||
|
||||
/* #undef NO_ITUNES_HACKS */
|
||||
#define WITH_ASF 1
|
||||
#define WITH_MP4 1
|
170
Frameworks/TagLib/taglib/taglib/ape/ape-tag-format.txt
Normal file
170
Frameworks/TagLib/taglib/taglib/ape/ape-tag-format.txt
Normal file
|
@ -0,0 +1,170 @@
|
|||
================================================================================
|
||||
= APE Tag Specification, Version 2.000
|
||||
================================================================================
|
||||
|
||||
Original Content (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de>
|
||||
Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org>
|
||||
|
||||
================================================================================
|
||||
= Contents
|
||||
================================================================================
|
||||
|
||||
1 - APE Tag General Structure
|
||||
2 - APE Tag Header / Footer Format
|
||||
3 - APE Tag Flags
|
||||
4 - APE Tag Item Format
|
||||
5 - APE Tag Item Supported Keys
|
||||
6 - APE Tag Item Content
|
||||
7 - Data Types
|
||||
7.1 - Data Types / UTF-8
|
||||
7.2 - Data Types / Dates
|
||||
7.3 - Data Types / Timestamps
|
||||
|
||||
================================================================================
|
||||
= 1 - APE Tag General Structure
|
||||
================================================================================
|
||||
|
||||
Member of Basic Components of SV8 Stream Note:
|
||||
|
||||
It is strongly recommended that the data size be stored in the tags. The size
|
||||
should normally be in the roughly one kilobyte, never more than 8 kilobytes.
|
||||
|
||||
Larger data should be stored externally using link entries. Linked data is much
|
||||
easier to process by normal programs, so for instance JPEG data should not be
|
||||
included inside the audio file.
|
||||
|
||||
APE Tag Version 2.000 (with header, recommended):
|
||||
|
||||
/================================\
|
||||
| APE Tag Header | 32 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Item 1 | > 10 bytes |
|
||||
| APE Tag Item 2 | > 10 bytes |
|
||||
| APE Tag Item n-1 | > 10 bytes |
|
||||
| APE Tag Item n | > 10 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Footer | 32 bytes |
|
||||
\================================/
|
||||
|
||||
|
||||
APE tag items should be sorted ascending by size. When streaming, parts of the
|
||||
APE tag may be dropped to reduce the danger of drop outs between tracks. This
|
||||
is not required, but is strongly recommended. It would be desirable for the i
|
||||
tems to be sorted by importance / size, but this is not feasible. This
|
||||
convention should only be broken when adding less important small items and it
|
||||
is not desirable to rewrite the entire tag. An APE tag at the end of a file
|
||||
(the recommended location) must have at least a footer; an APE tag at the
|
||||
beginning of a file (strongly discouraged) must have at least a header.
|
||||
|
||||
APE Tag Version 1.000 (without header, deprecated)
|
||||
|
||||
/================================\
|
||||
| APE Tag Item 1 | > 10 bytes |
|
||||
| APE Tag Item 2 | > 10 bytes |
|
||||
| APE Tag Item n-1 | > 10 bytes |
|
||||
| APE Tag Item n | > 10 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Footer | 32 bytes |
|
||||
\================================/
|
||||
|
||||
================================================================================
|
||||
= 2 - APE Tag Header / Footer Format
|
||||
================================================================================
|
||||
|
||||
Contains number, length and attributes of all tag items
|
||||
|
||||
Header and Footer are different in 1 bit in the Tags Flags to distinguish
|
||||
between them.
|
||||
|
||||
Member of APE Tag 2.0
|
||||
|
||||
/===========================================================================\
|
||||
| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Tag Size | 4 bytes | Tag size in bytes including footer and all tag |
|
||||
| | | items excluding the header (for 1.000 |
|
||||
| | | compatibility) |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Item Count | 4 bytes | Number of items in the tag |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Tag Flags | 4 bytes | Global flags |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Reserved | 8 bytes | Must be zeroed |
|
||||
\===========================================================================/
|
||||
|
||||
================================================================================
|
||||
= 3 - APE Tag Flags
|
||||
================================================================================
|
||||
|
||||
The general flag structure for either items or headers / footers is the same.
|
||||
Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are
|
||||
item specific.
|
||||
|
||||
Note: APE Tags from Version 1.0 do not use any of the following. All flags in
|
||||
that version are zeroed and ignored when reading.
|
||||
|
||||
/=================================================================\
|
||||
| Contains Header | Bit 31 | 1 - has header | 0 - no header |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Is Header | Bit 29 | 1 - is header | 0 - is footer |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Undefined | Bits 28 - 3 | Undefined, must be zeroed |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Encoding | Bits 2 - 1 | 00 - UTF-8 |
|
||||
| | | 01 - Binary Data * |
|
||||
| | | 10 - External Reference ** |
|
||||
| | | 11 - Reserved |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Read Only | Bit 0 | 1 - read only | 0 - read/write |
|
||||
\=================================================================/
|
||||
|
||||
(*) Should be ignored by tools for editing text values
|
||||
(**) Allowed external reference formats:
|
||||
- http://host/directory/filename.ext
|
||||
- ftp://host/directory/filename.ext
|
||||
- filename.ext
|
||||
- /directory/filename.ext
|
||||
- DRIVE:/directory/filename.ext
|
||||
|
||||
Note: External references are also UTF-8 encoded.
|
||||
|
||||
================================================================================
|
||||
= 4 - APE Tag Item Format
|
||||
================================================================================
|
||||
|
||||
APE Tag Items are stored as key-value pairs. APE Tags Item Key are case
|
||||
sensitive, however it is illegal to use keys which only differ in case and
|
||||
it is recommended that tag reading not be case sensitive.
|
||||
|
||||
Every key can only occur (at most) once. It is not possible to repeat a key
|
||||
to signify updated contents.
|
||||
|
||||
Tags can be partially or completely repeated in the streaming format. This
|
||||
makes it possible to display an artist and / or title if it was missed at the
|
||||
beginning of the stream. It is recommended that the important information like
|
||||
artist, album and title should occur approximately every 2 minutes in the
|
||||
stream and again 5 to 10 seconds before the end. However, care should be tak
|
||||
en not to replicate this information too often or during passages with high
|
||||
bitrate demands to avoid unnecessary drop-outs.
|
||||
|
||||
/==============================================================================\
|
||||
| Content Size | 4 bytes | Length of the value in bytes |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Flags | 4 bytes | Item flags |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Key | 2 - 255 bytes | Item key |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Key Terminator | 1 byte | Null byte that indicates the end of the key |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Value | variable | Content (formatted according to the flags) |
|
||||
\==============================================================================/
|
||||
|
||||
================================================================================
|
||||
|
||||
Sections 5 - 7 haven't yet been converted from:
|
||||
|
||||
http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
|
270
Frameworks/TagLib/taglib/taglib/ape/apefile.cpp
Normal file
270
Frameworks/TagLib/taglib/taglib/ape/apefile.cpp
Normal file
|
@ -0,0 +1,270 @@
|
|||
/***************************************************************************
|
||||
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 "apefile.h"
|
||||
|
||||
#include "apetag.h"
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { APEIndex, ID3v1Index };
|
||||
}
|
||||
|
||||
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;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
APE::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *APE::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
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>(ID3v1Index, create);
|
||||
}
|
||||
|
||||
APE::Tag *APE::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(APEIndex, create);
|
||||
}
|
||||
|
||||
void APE::File::strip(int tags)
|
||||
{
|
||||
if(tags & ID3v1) {
|
||||
d->tag.set(ID3v1Index, 0);
|
||||
APETag(true);
|
||||
}
|
||||
|
||||
if(tags & APE) {
|
||||
d->tag.set(APEIndex, 0);
|
||||
|
||||
if(!ID3v1Tag())
|
||||
APETag(true);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
|
||||
// Look for an APE tag
|
||||
|
||||
d->APELocation = findAPE();
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
d->tag.set(APEIndex, new APE::Tag(this, d->APELocation));
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
|
||||
d->hasAPE = true;
|
||||
}
|
||||
|
||||
if(!d->hasID3v1)
|
||||
APETag(true);
|
||||
|
||||
// Look for 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;
|
||||
}
|
171
Frameworks/TagLib/taglib/taglib/ape/apefile.h
Normal file
171
Frameworks/TagLib/taglib/taglib/ape/apefile.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
/***************************************************************************
|
||||
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 APE 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 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
|
||||
};
|
||||
|
||||
/*!
|
||||
* Contructs 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.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||
* or a combination of the two.
|
||||
*/
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the 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 will return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist. If there is already an APE tag, the
|
||||
* new ID3v1 tag will be placed after it.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* a APE tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
APE::Tag *APETag(bool create = false);
|
||||
|
||||
/*!
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it removes all tags.
|
||||
*
|
||||
* \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);
|
||||
|
||||
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
|
236
Frameworks/TagLib/taglib/taglib/ape/apefooter.cpp
Normal file
236
Frameworks/TagLib/taglib/taglib/ape/apefooter.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
(C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp)
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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 <ostream>
|
||||
#include <bitset>
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class Footer::FooterPrivate
|
||||
{
|
||||
public:
|
||||
FooterPrivate() : version(0),
|
||||
footerPresent(true),
|
||||
headerPresent(false),
|
||||
isHeader(false),
|
||||
itemCount(0),
|
||||
tagSize(0) {}
|
||||
|
||||
~FooterPrivate() {}
|
||||
|
||||
uint version;
|
||||
|
||||
bool footerPresent;
|
||||
bool headerPresent;
|
||||
|
||||
bool isHeader;
|
||||
|
||||
uint itemCount;
|
||||
uint tagSize;
|
||||
|
||||
static const uint size = 32;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TagLib::uint Footer::size()
|
||||
{
|
||||
return FooterPrivate::size;
|
||||
}
|
||||
|
||||
ByteVector Footer::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("APETAGEX");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Footer::Footer()
|
||||
{
|
||||
d = new FooterPrivate;
|
||||
}
|
||||
|
||||
Footer::Footer(const ByteVector &data)
|
||||
{
|
||||
d = new FooterPrivate;
|
||||
parse(data);
|
||||
}
|
||||
|
||||
Footer::~Footer()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
bool Footer::headerPresent() const
|
||||
{
|
||||
return d->headerPresent;
|
||||
}
|
||||
|
||||
bool Footer::footerPresent() const
|
||||
{
|
||||
return d->footerPresent;
|
||||
}
|
||||
|
||||
bool Footer::isHeader() const
|
||||
{
|
||||
return d->isHeader;
|
||||
}
|
||||
|
||||
void Footer::setHeaderPresent(bool b) const
|
||||
{
|
||||
d->headerPresent = b;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::itemCount() const
|
||||
{
|
||||
return d->itemCount;
|
||||
}
|
||||
|
||||
void Footer::setItemCount(uint s)
|
||||
{
|
||||
d->itemCount = s;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::tagSize() const
|
||||
{
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::completeTagSize() const
|
||||
{
|
||||
if(d->headerPresent)
|
||||
return d->tagSize + d->size;
|
||||
else
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
void Footer::setTagSize(uint s)
|
||||
{
|
||||
d->tagSize = s;
|
||||
}
|
||||
|
||||
void Footer::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
ByteVector Footer::renderFooter() const
|
||||
{
|
||||
return render(false);
|
||||
}
|
||||
|
||||
ByteVector Footer::renderHeader() const
|
||||
{
|
||||
if (!d->headerPresent) return ByteVector();
|
||||
|
||||
return render(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Footer::parse(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < size())
|
||||
return;
|
||||
|
||||
// The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".
|
||||
|
||||
// Read the version number
|
||||
|
||||
d->version = data.mid(8, 4).toUInt(false);
|
||||
|
||||
// Read the tag size
|
||||
|
||||
d->tagSize = data.mid(12, 4).toUInt(false);
|
||||
|
||||
// Read the item count
|
||||
|
||||
d->itemCount = data.mid(16, 4).toUInt(false);
|
||||
|
||||
// Read the flags
|
||||
|
||||
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(20, 4).toUInt(false)));
|
||||
|
||||
d->headerPresent = flags[31];
|
||||
d->footerPresent = !flags[30];
|
||||
d->isHeader = flags[29];
|
||||
|
||||
}
|
||||
|
||||
ByteVector Footer::render(bool isHeader) const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
// add the file identifier -- "APETAGEX"
|
||||
|
||||
v.append(fileIdentifier());
|
||||
|
||||
// add the version number -- we always render a 2.000 tag regardless of what
|
||||
// the tag originally was.
|
||||
|
||||
v.append(ByteVector::fromUInt(2000, false));
|
||||
|
||||
// add the tag size
|
||||
|
||||
v.append(ByteVector::fromUInt(d->tagSize, false));
|
||||
|
||||
// add the item count
|
||||
|
||||
v.append(ByteVector::fromUInt(d->itemCount, false));
|
||||
|
||||
// render and add the flags
|
||||
|
||||
std::bitset<32> flags;
|
||||
|
||||
flags[31] = d->headerPresent;
|
||||
flags[30] = false; // footer is always present
|
||||
flags[29] = isHeader;
|
||||
|
||||
v.append(ByteVector::fromUInt(flags.to_ulong(), false));
|
||||
|
||||
// add the reserved 64bit
|
||||
|
||||
v.append(ByteVector::fromLongLong(0));
|
||||
|
||||
return v;
|
||||
}
|
173
Frameworks/TagLib/taglib/taglib/ape/apefooter.h
Normal file
173
Frameworks/TagLib/taglib/taglib/ape/apefooter.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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
|
230
Frameworks/TagLib/taglib/taglib/ape/apeitem.cpp
Normal file
230
Frameworks/TagLib/taglib/taglib/ape/apeitem.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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 Item &item)
|
||||
{
|
||||
d = new ItemPrivate(*item.d);
|
||||
}
|
||||
|
||||
APE::Item::~Item()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Item &APE::Item::operator=(const Item &item)
|
||||
{
|
||||
delete d;
|
||||
d = new ItemPrivate(*item.d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void APE::Item::setReadOnly(bool readOnly)
|
||||
{
|
||||
d->readOnly = readOnly;
|
||||
}
|
||||
|
||||
bool APE::Item::isReadOnly() const
|
||||
{
|
||||
return d->readOnly;
|
||||
}
|
||||
|
||||
void APE::Item::setType(APE::Item::ItemTypes val)
|
||||
{
|
||||
d->type = val;
|
||||
}
|
||||
|
||||
APE::Item::ItemTypes APE::Item::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String APE::Item::key() const
|
||||
{
|
||||
return d->key;
|
||||
}
|
||||
|
||||
ByteVector APE::Item::value() const
|
||||
{
|
||||
// This seems incorrect as it won't be actually rendering the value to keep it
|
||||
// up to date.
|
||||
|
||||
return d->value;
|
||||
}
|
||||
|
||||
void APE::Item::setKey(const String &key)
|
||||
{
|
||||
d->key = key;
|
||||
}
|
||||
|
||||
void APE::Item::setValue(const String &value)
|
||||
{
|
||||
d->text = value;
|
||||
}
|
||||
|
||||
void APE::Item::setValues(const StringList &value)
|
||||
{
|
||||
d->text = value;
|
||||
}
|
||||
|
||||
void APE::Item::appendValue(const String &value)
|
||||
{
|
||||
d->text.append(value);
|
||||
}
|
||||
|
||||
void APE::Item::appendValues(const StringList &values)
|
||||
{
|
||||
d->text.append(values);
|
||||
}
|
||||
|
||||
int APE::Item::size() const
|
||||
{
|
||||
return 8 + d->key.size() + 1 + d->value.size();
|
||||
}
|
||||
|
||||
StringList APE::Item::toStringList() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
StringList APE::Item::values() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
String APE::Item::toString() const
|
||||
{
|
||||
return isEmpty() ? String::null : d->text.front();
|
||||
}
|
||||
|
||||
bool APE::Item::isEmpty() const
|
||||
{
|
||||
switch(d->type) {
|
||||
case Text:
|
||||
case Binary:
|
||||
if(d->text.isEmpty())
|
||||
return true;
|
||||
if(d->text.size() == 1 && d->text.front().isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
case Locator:
|
||||
return d->value.isEmpty();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void APE::Item::parse(const ByteVector &data)
|
||||
{
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
|
||||
if(data.size() < 11) {
|
||||
debug("APE::Item::parse() -- no data in item");
|
||||
return;
|
||||
}
|
||||
|
||||
uint valueLength = data.mid(0, 4).toUInt(false);
|
||||
uint flags = data.mid(4, 4).toUInt(false);
|
||||
|
||||
d->key = String(data.mid(8), String::UTF8);
|
||||
|
||||
d->value = data.mid(8 + d->key.size() + 1, valueLength);
|
||||
|
||||
setReadOnly(flags & 1);
|
||||
setType(ItemTypes((flags >> 1) & 3));
|
||||
|
||||
if(int(d->type) < 2)
|
||||
d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
|
||||
}
|
||||
|
||||
ByteVector APE::Item::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
|
||||
ByteVector value;
|
||||
|
||||
if(isEmpty())
|
||||
return data;
|
||||
|
||||
if(d->type == Text) {
|
||||
StringList::ConstIterator it = d->text.begin();
|
||||
|
||||
value.append(it->data(String::UTF8));
|
||||
it++;
|
||||
for(; it != d->text.end(); ++it) {
|
||||
value.append('\0');
|
||||
value.append(it->data(String::UTF8));
|
||||
}
|
||||
d->value = value;
|
||||
}
|
||||
else
|
||||
value.append(d->value);
|
||||
|
||||
data.append(ByteVector::fromUInt(value.size(), false));
|
||||
data.append(ByteVector::fromUInt(flags, false));
|
||||
data.append(d->key.data(String::UTF8));
|
||||
data.append(ByteVector('\0'));
|
||||
data.append(value);
|
||||
|
||||
return data;
|
||||
}
|
204
Frameworks/TagLib/taglib/taglib/ape/apeitem.h
Normal file
204
Frameworks/TagLib/taglib/taglib/ape/apeitem.h
Normal file
|
@ -0,0 +1,204 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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 an item with \a key and \a value.
|
||||
*/
|
||||
// BIC: Remove this, StringList has a constructor from a single string
|
||||
Item(const String &key, const String &value);
|
||||
|
||||
/*!
|
||||
* Constructs an item with \a key and \a values.
|
||||
*/
|
||||
Item(const String &key, const StringList &values);
|
||||
|
||||
/*!
|
||||
* Construct an item as a copy of \a item.
|
||||
*/
|
||||
Item(const Item &item);
|
||||
|
||||
/*!
|
||||
* Destroys the item.
|
||||
*/
|
||||
virtual ~Item();
|
||||
|
||||
/*!
|
||||
* Copies the contents of \a item into this item.
|
||||
*/
|
||||
Item &operator=(const Item &item);
|
||||
|
||||
/*!
|
||||
* Returns the key.
|
||||
*/
|
||||
String key() const;
|
||||
|
||||
/*!
|
||||
* Returns the binary value.
|
||||
*
|
||||
* \deprecated This will be removed in the next binary incompatible version
|
||||
* as it is not kept in sync with the things that are set using setValue()
|
||||
* and friends.
|
||||
*/
|
||||
ByteVector value() const;
|
||||
|
||||
/*!
|
||||
* Sets the key for the item to \a key.
|
||||
*/
|
||||
void setKey(const String &key);
|
||||
|
||||
/*!
|
||||
* Sets the value of the item to \a value and clears any previous contents.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void setValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Sets the value of the item to the list of values in \a value and clears
|
||||
* any previous contents.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
void setValues(const StringList &values);
|
||||
|
||||
/*!
|
||||
* Appends \a value to create (or extend) the current list of values.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void appendValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Appends \a values to extend the current list of values.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
void appendValues(const StringList &values);
|
||||
|
||||
/*!
|
||||
* Returns the size of the full item.
|
||||
*/
|
||||
int size() const;
|
||||
|
||||
/*!
|
||||
* Returns the value as a single string. In case of multiple strings,
|
||||
* the first is returned.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
* \see values
|
||||
*/
|
||||
StringList toStringList() const;
|
||||
|
||||
/*!
|
||||
* Returns the list of values.
|
||||
*/
|
||||
StringList values() const;
|
||||
|
||||
/*!
|
||||
* Render the item to a ByteVector.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Parse the item from the ByteVector \a data.
|
||||
*/
|
||||
void parse(const ByteVector& data);
|
||||
|
||||
/*!
|
||||
* Set the item to read-only.
|
||||
*/
|
||||
void setReadOnly(bool readOnly);
|
||||
|
||||
/*!
|
||||
* Return true if the item is read-only.
|
||||
*/
|
||||
bool isReadOnly() const;
|
||||
|
||||
/*!
|
||||
* Sets the type of the item to \a type.
|
||||
*
|
||||
* \see ItemTypes
|
||||
*/
|
||||
void setType(ItemTypes type);
|
||||
|
||||
/*!
|
||||
* Returns the type of the item.
|
||||
*/
|
||||
ItemTypes type() const;
|
||||
|
||||
/*!
|
||||
* Returns if the item has any real content.
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
class ItemPrivate;
|
||||
ItemPrivate *d;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
224
Frameworks/TagLib/taglib/taglib/ape/apeproperties.cpp
Normal file
224
Frameworks/TagLib/taglib/taglib/ape/apeproperties.cpp
Normal file
|
@ -0,0 +1,224 @@
|
|||
/***************************************************************************
|
||||
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),
|
||||
file(file),
|
||||
streamLength(streamLength) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int version;
|
||||
int bitsPerSample;
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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.mid(4).toUInt(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, 0);
|
||||
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);
|
||||
uint descriptorBytes = descriptor.mid(0,4).toUInt(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.mid(18, 2).toShort(false);
|
||||
d->sampleRate = header.mid(20, 4).toUInt(false);
|
||||
d->bitsPerSample = header.mid(16, 2).toShort(false);
|
||||
//d->compressionLevel =
|
||||
|
||||
uint totalFrames = header.mid(12, 4).toUInt(false);
|
||||
uint blocksPerFrame = header.mid(4, 4).toUInt(false);
|
||||
uint finalFrameBlocks = header.mid(8, 4).toUInt(false);
|
||||
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;
|
||||
}
|
||||
|
||||
void APE::Properties::analyzeOld()
|
||||
{
|
||||
ByteVector header = d->file->readBlock(26);
|
||||
uint totalFrames = header.mid(18, 4).toUInt(false);
|
||||
|
||||
// Fail on 0 length APE files (catches non-finalized APE files)
|
||||
if(totalFrames == 0)
|
||||
return;
|
||||
|
||||
short compressionLevel = header.mid(0, 2).toShort(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.mid(4, 2).toShort(false);
|
||||
d->sampleRate = header.mid(6, 4).toUInt(false);
|
||||
uint finalFrameBlocks = header.mid(22, 4).toUInt(false);
|
||||
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;
|
||||
}
|
||||
|
98
Frameworks/TagLib/taglib/taglib/ape/apeproperties.h
Normal file
98
Frameworks/TagLib/taglib/taglib/ape/apeproperties.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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
|
331
Frameworks/TagLib/taglib/taglib/ape/apetag.cpp
Normal file
331
Frameworks/TagLib/taglib/taglib/ape/apetag.cpp
Normal file
|
@ -0,0 +1,331 @@
|
|||
/***************************************************************************
|
||||
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 "apetag.h"
|
||||
#include "apefooter.h"
|
||||
#include "apeitem.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class APE::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() : file(0), footerLocation(-1), tagLength(0) {}
|
||||
|
||||
File *file;
|
||||
long footerLocation;
|
||||
long tagLength;
|
||||
|
||||
Footer footer;
|
||||
|
||||
ItemListMap itemListMap;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Tag::Tag() : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
APE::Tag::Tag(File *file, long footerLocation) : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->file = file;
|
||||
d->footerLocation = footerLocation;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
APE::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector APE::Tag::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("APETAGEX");
|
||||
}
|
||||
|
||||
String APE::Tag::title() const
|
||||
{
|
||||
if(d->itemListMap["TITLE"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["TITLE"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::artist() const
|
||||
{
|
||||
if(d->itemListMap["ARTIST"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["ARTIST"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::album() const
|
||||
{
|
||||
if(d->itemListMap["ALBUM"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["ALBUM"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::comment() const
|
||||
{
|
||||
if(d->itemListMap["COMMENT"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["COMMENT"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::genre() const
|
||||
{
|
||||
if(d->itemListMap["GENRE"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["GENRE"].toString();
|
||||
}
|
||||
|
||||
TagLib::uint APE::Tag::year() const
|
||||
{
|
||||
if(d->itemListMap["YEAR"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["YEAR"].toString().toInt();
|
||||
}
|
||||
|
||||
TagLib::uint APE::Tag::track() const
|
||||
{
|
||||
if(d->itemListMap["TRACK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["TRACK"].toString().toInt();
|
||||
}
|
||||
|
||||
float APE::Tag::rgAlbumGain() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgAlbumPeak() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_ALBUM_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_ALBUM_PEAK"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgTrackGain() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_TRACK_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_TRACK_GAIN"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgTrackPeak() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_TRACK_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_TRACK_PEAK"].toString().toFloat();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGAlbumGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_ALBUM_GAIN");
|
||||
else
|
||||
addValue("REPLAYGAIN_ALBUM_GAIN", String::number(f) + " dB", true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGAlbumPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_ALBUM_PEAK");
|
||||
else
|
||||
addValue("REPLAYGAIN_ALBUM_PEAK", String::number(f), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGTrackGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_TRACK_GAIN");
|
||||
else
|
||||
addValue("REPLAYGAIN_TRACK_GAIN", String::number(f) + " dB", true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGTrackPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_TRACK_PEAK");
|
||||
else
|
||||
addValue("REPLAYGAIN_TRACK_PEAK", String::number(f), true);
|
||||
}
|
||||
|
||||
APE::Footer *APE::Tag::footer() const
|
||||
{
|
||||
return &d->footer;
|
||||
}
|
||||
|
||||
const APE::ItemListMap& APE::Tag::itemListMap() const
|
||||
{
|
||||
return d->itemListMap;
|
||||
}
|
||||
|
||||
void APE::Tag::removeItem(const String &key)
|
||||
{
|
||||
Map<const String, Item>::Iterator it = d->itemListMap.find(key.upper());
|
||||
if(it != d->itemListMap.end())
|
||||
d->itemListMap.erase(it);
|
||||
}
|
||||
|
||||
void APE::Tag::addValue(const String &key, const String &value, bool replace)
|
||||
{
|
||||
if(replace)
|
||||
removeItem(key);
|
||||
if(!value.isEmpty()) {
|
||||
if(d->itemListMap.contains(key) || !replace)
|
||||
d->itemListMap[key.upper()].appendValue(value);
|
||||
else
|
||||
setItem(key, Item(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
void APE::Tag::setItem(const String &key, const Item &item)
|
||||
{
|
||||
d->itemListMap.insert(key.upper(), item);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
178
Frameworks/TagLib/taglib/taglib/ape/apetag.h
Normal file
178
Frameworks/TagLib/taglib/taglib/ape/apetag.h
Normal file
|
@ -0,0 +1,178 @@
|
|||
/***************************************************************************
|
||||
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 float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() 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 void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
/*!
|
||||
* 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 item specified by \a key the data \a value. If \a replace
|
||||
* is true, then all of the other values on the same key will be removed
|
||||
* first.
|
||||
*/
|
||||
void addValue(const String &key, const String &value, bool replace = true);
|
||||
|
||||
/*!
|
||||
* Sets the \a key item to the value of \a item. If an item with the \a key is already
|
||||
* present, it will be replaced.
|
||||
*/
|
||||
void setItem(const String &key, const Item &item);
|
||||
|
||||
/*!
|
||||
* 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
|
356
Frameworks/TagLib/taglib/taglib/asf/asfattribute.cpp
Normal file
356
Frameworks/TagLib/taglib/taglib/asf/asfattribute.cpp
Normal file
|
@ -0,0 +1,356 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "asfattribute.h"
|
||||
#include "asffile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Attribute::AttributePrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
AttributePrivate()
|
||||
: 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;
|
||||
}
|
||||
|
||||
#endif
|
203
Frameworks/TagLib/taglib/taglib/asf/asfattribute.h
Normal file
203
Frameworks/TagLib/taglib/taglib/asf/asfattribute.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
/**************************************************************************
|
||||
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
|
543
Frameworks/TagLib/taglib/taglib/asf/asffile.cpp
Normal file
543
Frameworks/TagLib/taglib/taglib/asf/asffile.cpp
Normal file
|
@ -0,0 +1,543 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tstring.h>
|
||||
#include "asffile.h"
|
||||
#include "asftag.h"
|
||||
#include "asfproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate():
|
||||
size(0),
|
||||
tag(0),
|
||||
properties(0),
|
||||
contentDescriptionObject(0),
|
||||
extendedContentDescriptionObject(0),
|
||||
headerExtensionObject(0),
|
||||
metadataObject(0),
|
||||
metadataLibraryObject(0) {}
|
||||
unsigned long long size;
|
||||
ASF::Tag *tag;
|
||||
ASF::Properties *properties;
|
||||
List<ASF::File::BaseObject *> objects;
|
||||
ASF::File::ContentDescriptionObject *contentDescriptionObject;
|
||||
ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
|
||||
ASF::File::HeaderExtensionObject *headerExtensionObject;
|
||||
ASF::File::MetadataObject *metadataObject;
|
||||
ASF::File::MetadataLibraryObject *metadataLibraryObject;
|
||||
};
|
||||
|
||||
static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
|
||||
static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
|
||||
static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
|
||||
static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
|
||||
|
||||
class ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector data;
|
||||
virtual ~BaseObject() {}
|
||||
virtual ByteVector guid() = 0;
|
||||
virtual void parse(ASF::File *file, unsigned int size);
|
||||
virtual ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::UnknownObject : public ASF::File::BaseObject
|
||||
{
|
||||
ByteVector myGuid;
|
||||
public:
|
||||
UnknownObject(const ByteVector &guid);
|
||||
ByteVector guid();
|
||||
};
|
||||
|
||||
class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
};
|
||||
|
||||
class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
};
|
||||
|
||||
class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::MetadataObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
List<ASF::File::BaseObject *> objects;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
void ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
|
||||
{
|
||||
data.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.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
|
||||
}
|
||||
|
||||
ByteVector ASF::File::StreamPropertiesObject::guid()
|
||||
{
|
||||
return streamPropertiesGuid;
|
||||
}
|
||||
|
||||
void ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
file->d->properties->setChannels(data.mid(56, 2).toShort(false));
|
||||
file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
|
||||
file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ContentDescriptionObject::guid()
|
||||
{
|
||||
return contentDescriptionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->contentDescriptionObject = this;
|
||||
int titleLength = file->readWORD();
|
||||
int artistLength = file->readWORD();
|
||||
int copyrightLength = file->readWORD();
|
||||
int commentLength = file->readWORD();
|
||||
int ratingLength = file->readWORD();
|
||||
file->d->tag->setTitle(file->readString(titleLength));
|
||||
file->d->tag->setArtist(file->readString(artistLength));
|
||||
file->d->tag->setCopyright(file->readString(copyrightLength));
|
||||
file->d->tag->setComment(file->readString(commentLength));
|
||||
file->d->tag->setRating(file->readString(ratingLength));
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
ByteVector v1 = file->renderString(file->d->tag->title());
|
||||
ByteVector v2 = file->renderString(file->d->tag->artist());
|
||||
ByteVector v3 = file->renderString(file->d->tag->copyright());
|
||||
ByteVector v4 = file->renderString(file->d->tag->comment());
|
||||
ByteVector v5 = file->renderString(file->d->tag->rating());
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(v1.size(), false));
|
||||
data.append(ByteVector::fromShort(v2.size(), false));
|
||||
data.append(ByteVector::fromShort(v3.size(), false));
|
||||
data.append(ByteVector::fromShort(v4.size(), false));
|
||||
data.append(ByteVector::fromShort(v5.size(), false));
|
||||
data.append(v1);
|
||||
data.append(v2);
|
||||
data.append(v3);
|
||||
data.append(v4);
|
||||
data.append(v5);
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ExtendedContentDescriptionObject::guid()
|
||||
{
|
||||
return extendedContentDescriptionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->extendedContentDescriptionObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataObject::guid()
|
||||
{
|
||||
return metadataGuid;
|
||||
}
|
||||
|
||||
void ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->metadataObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 1);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataLibraryObject::guid()
|
||||
{
|
||||
return metadataLibraryGuid;
|
||||
}
|
||||
|
||||
void ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->metadataLibraryObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 2);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataLibraryObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::HeaderExtensionObject::guid()
|
||||
{
|
||||
return headerExtensionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->headerExtensionObject = this;
|
||||
file->seek(18, File::Current);
|
||||
long long dataSize = file->readDWORD();
|
||||
long long dataPos = 0;
|
||||
while(dataPos < dataSize) {
|
||||
ByteVector guid = file->readBlock(16);
|
||||
long long size = file->readQWORD();
|
||||
BaseObject *obj;
|
||||
if(guid == metadataGuid) {
|
||||
obj = new MetadataObject();
|
||||
}
|
||||
else if(guid == metadataLibraryGuid) {
|
||||
obj = new MetadataLibraryObject();
|
||||
}
|
||||
else {
|
||||
obj = new UnknownObject(guid);
|
||||
}
|
||||
obj->parse(file, size);
|
||||
objects.append(obj);
|
||||
dataPos += size;
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::HeaderExtensionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
for(unsigned int i = 0; i < objects.size(); i++) {
|
||||
data.append(objects[i]->render(file));
|
||||
}
|
||||
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
: TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
ASF::File::~File()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->objects.size(); i++) {
|
||||
delete d->objects[i];
|
||||
}
|
||||
if(d->tag) {
|
||||
delete d->tag;
|
||||
}
|
||||
if(d->properties) {
|
||||
delete d->properties;
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
ASF::Tag *ASF::File::tag() const
|
||||
{
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
ASF::Properties *ASF::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
|
||||
{
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
ByteVector guid = readBlock(16);
|
||||
if(guid != headerGuid) {
|
||||
debug("ASF: Not an ASF file.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->tag = new ASF::Tag();
|
||||
d->properties = new ASF::Properties();
|
||||
|
||||
d->size = readQWORD();
|
||||
int numObjects = readDWORD();
|
||||
seek(2, Current);
|
||||
|
||||
for(int i = 0; i < numObjects; i++) {
|
||||
ByteVector guid = readBlock(16);
|
||||
long size = (long)readQWORD();
|
||||
BaseObject *obj;
|
||||
if(guid == filePropertiesGuid) {
|
||||
obj = new FilePropertiesObject();
|
||||
}
|
||||
else if(guid == streamPropertiesGuid) {
|
||||
obj = new StreamPropertiesObject();
|
||||
}
|
||||
else if(guid == contentDescriptionGuid) {
|
||||
obj = new ContentDescriptionObject();
|
||||
}
|
||||
else if(guid == extendedContentDescriptionGuid) {
|
||||
obj = new ExtendedContentDescriptionObject();
|
||||
}
|
||||
else if(guid == headerExtensionGuid) {
|
||||
obj = new HeaderExtensionObject();
|
||||
}
|
||||
else {
|
||||
obj = new UnknownObject(guid);
|
||||
}
|
||||
obj->parse(this, size);
|
||||
d->objects.append(obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool ASF::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("ASF: File is read-only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!d->contentDescriptionObject) {
|
||||
d->contentDescriptionObject = new ContentDescriptionObject();
|
||||
d->objects.append(d->contentDescriptionObject);
|
||||
}
|
||||
if(!d->extendedContentDescriptionObject) {
|
||||
d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
|
||||
d->objects.append(d->extendedContentDescriptionObject);
|
||||
}
|
||||
if(!d->headerExtensionObject) {
|
||||
d->headerExtensionObject = new HeaderExtensionObject();
|
||||
d->objects.append(d->headerExtensionObject);
|
||||
}
|
||||
if(!d->metadataObject) {
|
||||
d->metadataObject = new MetadataObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataObject);
|
||||
}
|
||||
if(!d->metadataLibraryObject) {
|
||||
d->metadataLibraryObject = new MetadataLibraryObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
|
||||
}
|
||||
|
||||
ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
|
||||
for(; it != d->tag->attributeListMap().end(); it++) {
|
||||
const String &name = it->first;
|
||||
const AttributeList &attributes = it->second;
|
||||
bool inExtendedContentDescriptionObject = false;
|
||||
bool inMetadataObject = false;
|
||||
for(unsigned int j = 0; j < attributes.size(); j++) {
|
||||
const Attribute &attribute = attributes[j];
|
||||
bool largeValue = attribute.dataSize() > 65535;
|
||||
if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
|
||||
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
|
||||
inExtendedContentDescriptionObject = true;
|
||||
}
|
||||
else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
|
||||
d->metadataObject->attributeData.append(attribute.render(name, 1));
|
||||
inMetadataObject = true;
|
||||
}
|
||||
else {
|
||||
d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector data;
|
||||
for(unsigned int i = 0; i < d->objects.size(); i++) {
|
||||
data.append(d->objects[i]->render(this));
|
||||
}
|
||||
data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
|
||||
insert(data, 0, d->size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ASF::File::readBYTE()
|
||||
{
|
||||
ByteVector v = readBlock(1);
|
||||
return v[0];
|
||||
}
|
||||
|
||||
int ASF::File::readWORD()
|
||||
{
|
||||
ByteVector v = readBlock(2);
|
||||
return v.toUShort(false);
|
||||
}
|
||||
|
||||
unsigned int ASF::File::readDWORD()
|
||||
{
|
||||
ByteVector v = readBlock(4);
|
||||
return v.toUInt(false);
|
||||
}
|
||||
|
||||
long long ASF::File::readQWORD()
|
||||
{
|
||||
ByteVector v = readBlock(8);
|
||||
return v.toLongLong(false);
|
||||
}
|
||||
|
||||
String ASF::File::readString(int length)
|
||||
{
|
||||
ByteVector data = readBlock(length);
|
||||
unsigned int size = data.size();
|
||||
while (size >= 2) {
|
||||
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
|
||||
break;
|
||||
}
|
||||
size -= 2;
|
||||
}
|
||||
if(size != data.size()) {
|
||||
data.resize(size);
|
||||
}
|
||||
return String(data, String::UTF16LE);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::renderString(const String &str, bool includeLength)
|
||||
{
|
||||
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
|
||||
if(includeLength) {
|
||||
data = ByteVector::fromShort(data.size(), false) + data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif
|
120
Frameworks/TagLib/taglib/taglib/asf/asffile.h
Normal file
120
Frameworks/TagLib/taglib/taglib/asf/asffile.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/**************************************************************************
|
||||
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:
|
||||
|
||||
/*!
|
||||
* Contructs an ASF file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ASF tag of the file.
|
||||
*
|
||||
* ASF::Tag implements the tag interface, so this serves as the
|
||||
* reimplementation of TagLib::File::tag().
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the ASF::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
virtual Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the ASF audio properties for this file.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
private:
|
||||
|
||||
int readBYTE();
|
||||
int readWORD();
|
||||
unsigned int readDWORD();
|
||||
long long readQWORD();
|
||||
static ByteVector renderString(const String &str, bool includeLength = false);
|
||||
String readString(int len);
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
|
||||
friend class Attribute;
|
||||
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
|
107
Frameworks/TagLib/taglib/taglib/asf/asfproperties.cpp
Normal file
107
Frameworks/TagLib/taglib/taglib/asf/asfproperties.cpp
Normal file
|
@ -0,0 +1,107 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "asfproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0) {}
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Properties::Properties() : AudioProperties(AudioProperties::Average)
|
||||
{
|
||||
d = new PropertiesPrivate;
|
||||
}
|
||||
|
||||
ASF::Properties::~Properties()
|
||||
{
|
||||
if(d)
|
||||
delete d;
|
||||
}
|
||||
|
||||
int ASF::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int ASF::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int ASF::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int ASF::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ASF::Properties::setLength(int length)
|
||||
{
|
||||
d->length = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setBitrate(int length)
|
||||
{
|
||||
d->bitrate = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setSampleRate(int length)
|
||||
{
|
||||
d->sampleRate = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setChannels(int length)
|
||||
{
|
||||
d->channels = length;
|
||||
}
|
||||
|
||||
#endif
|
74
Frameworks/TagLib/taglib/taglib/asf/asfproperties.h
Normal file
74
Frameworks/TagLib/taglib/taglib/asf/asfproperties.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
void setLength(int value);
|
||||
void setBitrate(int value);
|
||||
void setSampleRate(int value);
|
||||
void setChannels(int value);
|
||||
#endif
|
||||
|
||||
private:
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
245
Frameworks/TagLib/taglib/taglib/asf/asftag.cpp
Normal file
245
Frameworks/TagLib/taglib/taglib/asf/asftag.cpp
Normal file
|
@ -0,0 +1,245 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include "asftag.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
String title;
|
||||
String artist;
|
||||
String copyright;
|
||||
String comment;
|
||||
String rating;
|
||||
AttributeListMap attributeListMap;
|
||||
};
|
||||
|
||||
ASF::Tag::Tag()
|
||||
: TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
ASF::Tag::~Tag()
|
||||
{
|
||||
if(d)
|
||||
delete d;
|
||||
}
|
||||
|
||||
String ASF::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String ASF::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String ASF::Tag::album() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/AlbumTitle"))
|
||||
return d->attributeListMap["WM/AlbumTitle"][0].toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String ASF::Tag::copyright() const
|
||||
{
|
||||
return d->copyright;
|
||||
}
|
||||
|
||||
String ASF::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String ASF::Tag::rating() const
|
||||
{
|
||||
return d->rating;
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::year() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Year"))
|
||||
return d->attributeListMap["WM/Year"][0].toString().toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::track() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/TrackNumber")) {
|
||||
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
|
||||
if(attr.type() == ASF::Attribute::DWordType)
|
||||
return attr.toUInt();
|
||||
else
|
||||
return attr.toString().toInt();
|
||||
}
|
||||
if(d->attributeListMap.contains("WM/Track"))
|
||||
return d->attributeListMap["WM/Track"][0].toUInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ASF::Tag::genre() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Genre"))
|
||||
return d->attributeListMap["WM/Genre"][0].toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
float
|
||||
ASF::Tag::rgAlbumGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float
|
||||
ASF::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float
|
||||
ASF::Tag::rgTrackGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float
|
||||
ASF::Tag::rgTrackPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setRGAlbumGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setRGAlbumPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setRGTrackGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setRGTrackPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
ASF::AttributeListMap& ASF::Tag::attributeListMap()
|
||||
{
|
||||
return d->attributeListMap;
|
||||
}
|
||||
|
||||
void ASF::Tag::removeItem(const String &key)
|
||||
{
|
||||
AttributeListMap::Iterator it = d->attributeListMap.find(key);
|
||||
if(it != d->attributeListMap.end())
|
||||
d->attributeListMap.erase(it);
|
||||
}
|
||||
|
||||
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
AttributeList value;
|
||||
value.append(attribute);
|
||||
d->attributeListMap.insert(name, value);
|
||||
}
|
||||
|
||||
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
if(d->attributeListMap.contains(name)) {
|
||||
d->attributeListMap[name].append(attribute);
|
||||
}
|
||||
else {
|
||||
setAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
bool ASF::Tag::isEmpty() const
|
||||
{
|
||||
return TagLib::Tag::isEmpty() &&
|
||||
copyright().isEmpty() &&
|
||||
rating().isEmpty() &&
|
||||
d->attributeListMap.isEmpty();
|
||||
}
|
||||
|
||||
#endif
|
196
Frameworks/TagLib/taglib/taglib/asf/asftag.h
Normal file
196
Frameworks/TagLib/taglib/taglib/asf/asftag.h
Normal file
|
@ -0,0 +1,196 @@
|
|||
/**************************************************************************
|
||||
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;
|
||||
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() 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);
|
||||
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
/*!
|
||||
* Returns true if the tag does not contain any data. This should be
|
||||
* reimplemented in subclasses that provide more than the basic tagging
|
||||
* abilities in this class.
|
||||
*/
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the item list map. This is an AttributeListMap of
|
||||
* all of the items in the tag.
|
||||
*
|
||||
* This is the most powerfull structure for accessing the items of the tag.
|
||||
*/
|
||||
AttributeListMap &attributeListMap();
|
||||
|
||||
/*!
|
||||
* Removes the \a key attribute from the tag
|
||||
*/
|
||||
void removeItem(const String &name);
|
||||
|
||||
/*!
|
||||
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||
* with the \a key is already present, it will be replaced.
|
||||
*/
|
||||
void setAttribute(const String &name, const Attribute &attribute);
|
||||
|
||||
/*!
|
||||
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||
* with the \a key is already present, it will be added to the list.
|
||||
*/
|
||||
void addAttribute(const String &name, const Attribute &attribute);
|
||||
|
||||
private:
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
51
Frameworks/TagLib/taglib/taglib/audioproperties.cpp
Normal file
51
Frameworks/TagLib/taglib/taglib/audioproperties.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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)
|
||||
{
|
||||
|
||||
}
|
110
Frameworks/TagLib/taglib/taglib/audioproperties.h
Normal file
110
Frameworks/TagLib/taglib/taglib/audioproperties.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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
|
282
Frameworks/TagLib/taglib/taglib/fileref.cpp
Normal file
282
Frameworks/TagLib/taglib/taglib/fileref.cpp
Normal file
|
@ -0,0 +1,282 @@
|
|||
/***************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tfile.h>
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "fileref.h"
|
||||
#include "asffile.h"
|
||||
#include "mpegfile.h"
|
||||
#include "vorbisfile.h"
|
||||
#include "flacfile.h"
|
||||
#include "oggflacfile.h"
|
||||
#include "mpcfile.h"
|
||||
#include "mp4file.h"
|
||||
#include "wavpackfile.h"
|
||||
#include "speexfile.h"
|
||||
#include "opusfile.h"
|
||||
#include "trueaudiofile.h"
|
||||
#include "aifffile.h"
|
||||
#include "wavfile.h"
|
||||
#include "apefile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FileRef::FileRefPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
FileRefPrivate(File *f) : RefCounter(), file(f) {}
|
||||
~FileRefPrivate() {
|
||||
delete file;
|
||||
}
|
||||
|
||||
File *file;
|
||||
static List<const FileTypeResolver *> fileTypeResolvers;
|
||||
};
|
||||
|
||||
List<const FileRef::FileTypeResolver *> FileRef::FileRefPrivate::fileTypeResolvers;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FileRef::FileRef()
|
||||
{
|
||||
d = new FileRefPrivate(0);
|
||||
}
|
||||
|
||||
FileRef::FileRef(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle));
|
||||
}
|
||||
|
||||
FileRef::FileRef(File *file)
|
||||
{
|
||||
d = new FileRefPrivate(file);
|
||||
}
|
||||
|
||||
FileRef::FileRef(const FileRef &ref) : d(ref.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
FileRef::~FileRef()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
Tag *FileRef::tag() const
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::tag() - Called without a valid file.");
|
||||
return 0;
|
||||
}
|
||||
return d->file->tag();
|
||||
}
|
||||
|
||||
AudioProperties *FileRef::audioProperties() const
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::audioProperties() - Called without a valid file.");
|
||||
return 0;
|
||||
}
|
||||
return d->file->audioProperties();
|
||||
}
|
||||
|
||||
File *FileRef::file() const
|
||||
{
|
||||
return d->file;
|
||||
}
|
||||
|
||||
bool FileRef::save()
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::save() - Called without a valid file.");
|
||||
return false;
|
||||
}
|
||||
return d->file->save();
|
||||
}
|
||||
|
||||
const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static
|
||||
{
|
||||
FileRefPrivate::fileTypeResolvers.prepend(resolver);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
StringList FileRef::defaultFileExtensions()
|
||||
{
|
||||
StringList l;
|
||||
|
||||
l.append("ogg");
|
||||
l.append("flac");
|
||||
l.append("oga");
|
||||
l.append("mp3");
|
||||
l.append("mpc");
|
||||
l.append("wv");
|
||||
l.append("spx");
|
||||
l.append("tta");
|
||||
#ifdef TAGLIB_WITH_MP4
|
||||
l.append("m4a");
|
||||
l.append("m4b");
|
||||
l.append("m4p");
|
||||
l.append("3g2");
|
||||
l.append("mp4");
|
||||
#endif
|
||||
#ifdef TAGLIB_WITH_ASF
|
||||
l.append("wma");
|
||||
l.append("asf");
|
||||
#endif
|
||||
l.append("aif");
|
||||
l.append("aiff");
|
||||
l.append("wav");
|
||||
l.append("ape");
|
||||
l.append("ac3");
|
||||
l.append("opus");
|
||||
l.append("tak");
|
||||
l.append("ac3");
|
||||
l.append("apl");
|
||||
l.append("dts");
|
||||
l.append("dtshd");
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
bool FileRef::isNull() const
|
||||
{
|
||||
return !d->file || !d->file->isValid();
|
||||
}
|
||||
|
||||
FileRef &FileRef::operator=(const FileRef &ref)
|
||||
{
|
||||
if(&ref == this)
|
||||
return *this;
|
||||
|
||||
if(d->deref())
|
||||
delete d;
|
||||
|
||||
d = ref.d;
|
||||
d->ref();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool FileRef::operator==(const FileRef &ref) const
|
||||
{
|
||||
return ref.d->file == d->file;
|
||||
}
|
||||
|
||||
bool FileRef::operator!=(const FileRef &ref) const
|
||||
{
|
||||
return ref.d->file != d->file;
|
||||
}
|
||||
|
||||
File *FileRef::create(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) // static
|
||||
{
|
||||
|
||||
List<const FileTypeResolver *>::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin();
|
||||
|
||||
for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) {
|
||||
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(file)
|
||||
return file;
|
||||
}
|
||||
|
||||
// Ok, this is really dumb for now, but it works for testing.
|
||||
|
||||
String s;
|
||||
|
||||
#ifdef _WIN32
|
||||
s = (wcslen((const wchar_t *) fileName) > 0) ? String((const wchar_t *) fileName) : String((const char *) fileName);
|
||||
#else
|
||||
s = fileName;
|
||||
#endif
|
||||
|
||||
// If this list is updated, the method defaultFileExtensions() should also be
|
||||
// updated. However at some point that list should be created at the same time
|
||||
// that a default file type resolver is created.
|
||||
|
||||
int pos = s.rfind(".");
|
||||
if(pos != -1) {
|
||||
String ext = s.substr(pos + 1).upper();
|
||||
if(ext == "MP3")
|
||||
return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "OGG")
|
||||
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "OPUS")
|
||||
return new Ogg::Opus::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;
|
||||
file = new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if (file->isValid())
|
||||
return file;
|
||||
delete file;
|
||||
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
if(ext == "FLAC")
|
||||
return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "MPC")
|
||||
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WV")
|
||||
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "SPX")
|
||||
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "TTA")
|
||||
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
#ifdef TAGLIB_WITH_MP4
|
||||
if(ext == "M4A" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2")
|
||||
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
#endif
|
||||
#ifdef TAGLIB_WITH_ASF
|
||||
if(ext == "WMA" || ext == "ASF")
|
||||
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
#endif
|
||||
if(ext == "AIF" || 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);
|
||||
if(ext == "TAK" || ext == "AC3" || ext == "APL" || ext == "DTS" || ext == "DTSHD")
|
||||
return new APE::File(fileName, false, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
263
Frameworks/TagLib/taglib/taglib/fileref.h
Normal file
263
Frameworks/TagLib/taglib/taglib/fileref.h
Normal file
|
@ -0,0 +1,263 @@
|
|||
/***************************************************************************
|
||||
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
|
499
Frameworks/TagLib/taglib/taglib/flac/flacfile.cpp
Normal file
499
Frameworks/TagLib/taglib/taglib/flac/flacfile.cpp
Normal file
|
@ -0,0 +1,499 @@
|
|||
/***************************************************************************
|
||||
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 <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 { XiphIndex = 0, ID3v2Index = 1, ID3v1Index = 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()
|
||||
{
|
||||
for(uint i = 0; i < blocks.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;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
d->ID3v2FrameFactory = frameFactory;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
FLAC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *FLAC::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
FLAC::Properties *FLAC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
|
||||
bool FLAC::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("FLAC::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isValid()) {
|
||||
debug("FLAC::File::save() -- Trying to save invalid file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create new vorbis comments
|
||||
|
||||
Tag::duplicate(&d->tag, xiphComment(true), true);
|
||||
|
||||
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
|
||||
block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData);
|
||||
foundVorbisCommentBlock = true;
|
||||
}
|
||||
if(block->code() == MetadataBlock::Padding) {
|
||||
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] = 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[ID3v2Index])
|
||||
return static_cast<ID3v2::Tag *>(d->tag[ID3v2Index]);
|
||||
|
||||
d->tag.set(ID3v2Index, new ID3v2::Tag);
|
||||
return static_cast<ID3v2::Tag *>(d->tag[ID3v2Index]);
|
||||
}
|
||||
|
||||
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
|
||||
}
|
||||
|
||||
Ogg::XiphComment *FLAC::File::xiphComment(bool create)
|
||||
{
|
||||
return d->tag.access<Ogg::XiphComment>(XiphIndex, create);
|
||||
}
|
||||
|
||||
void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
|
||||
{
|
||||
d->ID3v2FrameFactory = factory;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
{
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = findID3v2();
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
|
||||
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
|
||||
|
||||
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
|
||||
|
||||
if(ID3v2Tag()->header()->tagSize() <= 0)
|
||||
d->tag.set(ID3v2Index, 0);
|
||||
else
|
||||
d->hasID3v2 = true;
|
||||
}
|
||||
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = findID3v1();
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
|
||||
// Look for FLAC metadata, including vorbis comments
|
||||
|
||||
scan();
|
||||
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
if(d->hasXiphComment)
|
||||
d->tag.set(XiphIndex, new Ogg::XiphComment(xiphCommentData()));
|
||||
else
|
||||
d->tag.set(XiphIndex, new Ogg::XiphComment);
|
||||
|
||||
if(readProperties)
|
||||
d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle);
|
||||
}
|
||||
|
||||
ByteVector FLAC::File::streamInfoData()
|
||||
{
|
||||
return isValid() ? d->streamInfoData : ByteVector();
|
||||
}
|
||||
|
||||
ByteVector FLAC::File::xiphCommentData() const
|
||||
{
|
||||
return (isValid() && d->hasXiphComment) ? d->xiphCommentData : ByteVector();
|
||||
}
|
||||
|
||||
long FLAC::File::streamLength()
|
||||
{
|
||||
return d->streamLength;
|
||||
}
|
||||
|
||||
void FLAC::File::scan()
|
||||
{
|
||||
// Scan the metadata pages
|
||||
|
||||
if(d->scanned)
|
||||
return;
|
||||
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
long nextBlockOffset;
|
||||
|
||||
if(d->hasID3v2)
|
||||
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
|
||||
else
|
||||
nextBlockOffset = find("fLaC");
|
||||
|
||||
if(nextBlockOffset < 0) {
|
||||
debug("FLAC::File::scan() -- FLAC stream not found");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
nextBlockOffset += 4;
|
||||
d->flacStart = nextBlockOffset;
|
||||
|
||||
seek(nextBlockOffset);
|
||||
|
||||
ByteVector header = readBlock(4);
|
||||
|
||||
// Header format (from spec):
|
||||
// <1> Last-metadata-block flag
|
||||
// <7> BLOCK_TYPE
|
||||
// 0 : STREAMINFO
|
||||
// 1 : PADDING
|
||||
// ..
|
||||
// 4 : VORBIS_COMMENT
|
||||
// ..
|
||||
// <24> Length of metadata to follow
|
||||
|
||||
char blockType = header[0] & 0x7f;
|
||||
bool isLastBlock = (header[0] & 0x80) != 0;
|
||||
uint length = header.mid(1, 3).toUInt();
|
||||
|
||||
// First block should be the stream_info metadata
|
||||
|
||||
if(blockType != 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.mid(1, 3).toUInt();
|
||||
|
||||
ByteVector data = readBlock(length);
|
||||
if(data.size() != length) {
|
||||
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::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;
|
||||
}
|
||||
|
222
Frameworks/TagLib/taglib/taglib/flac/flacfile.h
Normal file
222
Frameworks/TagLib/taglib/taglib/flac/flacfile.h
Normal file
|
@ -0,0 +1,222 @@
|
|||
/***************************************************************************
|
||||
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 "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:
|
||||
/*!
|
||||
* Contructs a FLAC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \deprecated This constructor will be dropped in favor of the one below
|
||||
* in a future version.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a FLAC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using
|
||||
* \a frameFactory.
|
||||
*/
|
||||
// BIC: merge with the above constructor
|
||||
File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be a union of XiphComment,
|
||||
* ID3v1 and ID3v2 tags.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
* \see ID3v1Tag()
|
||||
* \see XiphComment()
|
||||
*/
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the FLAC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file. This will primarily save the XiphComment, but
|
||||
* will also keep any old ID3-tags up to date. If the file
|
||||
* has no XiphComment, one will be constructed from the ID3-tags.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v2 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v2 tag. If \a create is true it will create
|
||||
* an ID3v2 tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v2::Tag *ID3v2Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the XiphComment for the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid XiphComment. If \a create is true it will create
|
||||
* a XiphComment if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
Ogg::XiphComment *xiphComment(bool create = false);
|
||||
|
||||
/*!
|
||||
* Set the ID3v2::FrameFactory to something other than the default. This
|
||||
* can be used to specify the way that ID3v2 frames will be interpreted
|
||||
* when
|
||||
*
|
||||
* \see ID3v2FrameFactory
|
||||
*/
|
||||
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
|
||||
|
||||
/*!
|
||||
* Returns the block of data used by FLAC::Properties for parsing the
|
||||
* stream properties.
|
||||
*
|
||||
* \deprecated This method will not be public in a future release.
|
||||
*/
|
||||
ByteVector streamInfoData(); // BIC: remove
|
||||
|
||||
/*!
|
||||
* Returns the length of the audio-stream, used by FLAC::Properties for
|
||||
* calculating the bitrate.
|
||||
*
|
||||
* \deprecated This method will not be public in a future release.
|
||||
*/
|
||||
long streamLength(); // BIC: remove
|
||||
|
||||
/*!
|
||||
* Returns a list of pictures attached to the FLAC file.
|
||||
*/
|
||||
List<Picture *> pictureList();
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
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
|
158
Frameworks/TagLib/taglib/taglib/flac/flacproperties.cpp
Normal file
158
Frameworks/TagLib/taglib/taglib/flac/flacproperties.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
/***************************************************************************
|
||||
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) {}
|
||||
|
||||
ByteVector data;
|
||||
long streamLength;
|
||||
ReadStyle style;
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int sampleWidth;
|
||||
int channels;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
|
||||
// Minimum block size (in samples)
|
||||
pos += 2;
|
||||
|
||||
// Maximum block size (in samples)
|
||||
pos += 2;
|
||||
|
||||
// Minimum frame size (in bytes)
|
||||
pos += 3;
|
||||
|
||||
// Maximum frame size (in bytes)
|
||||
pos += 3;
|
||||
|
||||
uint flags = d->data.mid(pos, 4).toUInt(true);
|
||||
d->sampleRate = flags >> 12;
|
||||
d->channels = ((flags >> 9) & 7) + 1;
|
||||
d->sampleWidth = ((flags >> 4) & 31) + 1;
|
||||
|
||||
// The last 4 bits are the most significant 4 bits for the 36 bit
|
||||
// stream length in samples. (Audio files measured in days)
|
||||
|
||||
uint highLength =d->sampleRate > 0 ? (((flags & 0xf) << 28) / d->sampleRate) << 4 : 0;
|
||||
pos += 4;
|
||||
|
||||
d->length = d->sampleRate > 0 ?
|
||||
(d->data.mid(pos, 4).toUInt(true)) / d->sampleRate + highLength : 0;
|
||||
pos += 4;
|
||||
|
||||
// Uncompressed bitrate:
|
||||
|
||||
//d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth;
|
||||
|
||||
// Real bitrate:
|
||||
|
||||
d->bitrate = d->length > 0 ? ((d->streamLength * 8UL) / d->length) / 1000 : 0;
|
||||
|
||||
d->signature = d->data.mid(pos, 32);
|
||||
}
|
98
Frameworks/TagLib/taglib/taglib/flac/flacproperties.h
Normal file
98
Frameworks/TagLib/taglib/taglib/flac/flacproperties.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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
|
325
Frameworks/TagLib/taglib/taglib/mpc/mpcfile.cpp
Normal file
325
Frameworks/TagLib/taglib/taglib/mpc/mpcfile.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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 "mpcfile.h"
|
||||
#include "id3v1tag.h"
|
||||
#include "id3v2header.h"
|
||||
#include "apetag.h"
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { APEIndex, ID3v1Index };
|
||||
}
|
||||
|
||||
class MPC::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
APELocation(-1),
|
||||
APESize(0),
|
||||
ID3v1Location(-1),
|
||||
ID3v2Header(0),
|
||||
ID3v2Location(-1),
|
||||
ID3v2Size(0),
|
||||
properties(0),
|
||||
scanned(false),
|
||||
hasAPE(false),
|
||||
hasID3v1(false),
|
||||
hasID3v2(false) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete ID3v2Header;
|
||||
delete properties;
|
||||
}
|
||||
|
||||
long APELocation;
|
||||
uint APESize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
ID3v2::Header *ID3v2Header;
|
||||
long ID3v2Location;
|
||||
uint ID3v2Size;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
bool scanned;
|
||||
|
||||
// These indicate whether the file *on disk* has these tags, not if
|
||||
// this data structure does. This is used in computing offsets.
|
||||
|
||||
bool hasAPE;
|
||||
bool hasID3v1;
|
||||
bool hasID3v2;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::File::File(FileName file, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
MPC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *MPC::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
MPC::Properties *MPC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool MPC::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("MPC::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Possibly strip ID3v2 tag
|
||||
|
||||
if(d->hasID3v2 && !d->ID3v2Header) {
|
||||
removeBlock(d->ID3v2Location, d->ID3v2Size);
|
||||
d->hasID3v2 = false;
|
||||
if(d->hasID3v1)
|
||||
d->ID3v1Location -= d->ID3v2Size;
|
||||
if(d->hasAPE)
|
||||
d->APELocation -= d->ID3v2Size;
|
||||
}
|
||||
|
||||
// Update ID3v1 tag
|
||||
|
||||
if(ID3v1Tag()) {
|
||||
if(d->hasID3v1) {
|
||||
seek(d->ID3v1Location);
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->ID3v1Location = tell();
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
} else
|
||||
if(d->hasID3v1) {
|
||||
removeBlock(d->ID3v1Location, 128);
|
||||
d->hasID3v1 = false;
|
||||
if(d->hasAPE) {
|
||||
if(d->APELocation > d->ID3v1Location)
|
||||
d->APELocation -= 128;
|
||||
}
|
||||
}
|
||||
|
||||
// Update APE tag
|
||||
|
||||
if(APETag()) {
|
||||
if(d->hasAPE)
|
||||
insert(APETag()->render(), d->APELocation, d->APESize);
|
||||
else {
|
||||
if(d->hasID3v1) {
|
||||
insert(APETag()->render(), d->ID3v1Location, 0);
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->hasAPE = true;
|
||||
d->APELocation = d->ID3v1Location;
|
||||
d->ID3v1Location += d->APESize;
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->APELocation = tell();
|
||||
writeBlock(APETag()->render());
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->hasAPE = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if(d->hasAPE) {
|
||||
removeBlock(d->APELocation, d->APESize);
|
||||
d->hasAPE = false;
|
||||
if(d->hasID3v1) {
|
||||
if(d->ID3v1Location > d->APELocation)
|
||||
d->ID3v1Location -= d->APESize;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v1::Tag *MPC::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
|
||||
}
|
||||
|
||||
APE::Tag *MPC::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(APEIndex, create);
|
||||
}
|
||||
|
||||
void MPC::File::strip(int tags)
|
||||
{
|
||||
if(tags & ID3v1) {
|
||||
d->tag.set(ID3v1Index, 0);
|
||||
APETag(true);
|
||||
}
|
||||
|
||||
if(tags & ID3v2) {
|
||||
delete d->ID3v2Header;
|
||||
d->ID3v2Header = 0;
|
||||
}
|
||||
|
||||
if(tags & APE) {
|
||||
d->tag.set(APEIndex, 0);
|
||||
|
||||
if(!ID3v1Tag())
|
||||
APETag(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MPC::File::remove(int tags)
|
||||
{
|
||||
strip(tags);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
|
||||
{
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = findID3v1();
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
|
||||
// Look for an APE tag
|
||||
|
||||
findAPE();
|
||||
|
||||
d->APELocation = findAPE();
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
d->tag.set(APEIndex, new APE::Tag(this, d->APELocation));
|
||||
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
|
||||
d->hasAPE = true;
|
||||
}
|
||||
|
||||
if(!d->hasID3v1)
|
||||
APETag(true);
|
||||
|
||||
// Look for and skip an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = findID3v2();
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
seek(d->ID3v2Location);
|
||||
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
|
||||
d->ID3v2Size = d->ID3v2Header->completeTagSize();
|
||||
d->hasID3v2 = true;
|
||||
}
|
||||
|
||||
if(d->hasID3v2)
|
||||
seek(d->ID3v2Location + d->ID3v2Size);
|
||||
else
|
||||
seek(0);
|
||||
|
||||
// Look for MPC metadata
|
||||
|
||||
if(readProperties) {
|
||||
d->properties = new Properties(readBlock(MPC::HeaderSize),
|
||||
length() - d->ID3v2Size - d->APESize);
|
||||
}
|
||||
}
|
||||
|
||||
long MPC::File::findAPE()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
if(d->hasID3v1)
|
||||
seek(-160, End);
|
||||
else
|
||||
seek(-32, End);
|
||||
|
||||
long p = tell();
|
||||
|
||||
if(readBlock(8) == APE::Tag::fileIdentifier())
|
||||
return p;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
long MPC::File::findID3v1()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
seek(-128, End);
|
||||
long p = tell();
|
||||
|
||||
if(readBlock(3) == ID3v1::Tag::fileIdentifier())
|
||||
return p;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
long MPC::File::findID3v2()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
seek(0);
|
||||
|
||||
if(readBlock(3) == ID3v2::Header::fileIdentifier())
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
175
Frameworks/TagLib/taglib/taglib/mpc/mpcfile.h
Normal file
175
Frameworks/TagLib/taglib/taglib/mpc/mpcfile.h
Normal file
|
@ -0,0 +1,175 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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 "mpcproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace ID3v1 { class Tag; }
|
||||
namespace APE { class Tag; }
|
||||
|
||||
//! An implementation of MPC metadata
|
||||
|
||||
/*!
|
||||
* This is implementation of MPC metadata.
|
||||
*
|
||||
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream
|
||||
* properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped
|
||||
* and ignored.
|
||||
*/
|
||||
|
||||
namespace MPC {
|
||||
|
||||
//! An implementation of TagLib::File with MPC specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for MPC files to the
|
||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||
* the abstract TagLib::File API as well as providing some additional
|
||||
* information specific to MPC files.
|
||||
* The only invalid tag combination supported is an ID3v1 tag after an APE tag.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
NoTags = 0x0000,
|
||||
//! Matches ID3v1 tags.
|
||||
ID3v1 = 0x0001,
|
||||
//! Matches ID3v2 tags.
|
||||
ID3v2 = 0x0002,
|
||||
//! Matches APE tags.
|
||||
APE = 0x0004,
|
||||
//! Matches all tag types.
|
||||
AllTags = 0xffff
|
||||
};
|
||||
|
||||
/*!
|
||||
* Contructs an MPC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||
* or a combination of the two.
|
||||
*/
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the MPC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Saves the file.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist. If there is already an APE tag, the
|
||||
* new ID3v1 tag will be placed after it.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* a APE tag if one does not exist. If there is already an ID3v1 tag, thes
|
||||
* new APE tag will be placed before it.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
APE::Tag *APETag(bool create = false);
|
||||
|
||||
/*!
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it removes all tags.
|
||||
*
|
||||
* \warning This will also invalidate pointers to the tags
|
||||
* as their memory will be freed.
|
||||
*
|
||||
* \note In order to make the removal permanent save() still needs to be called.
|
||||
*/
|
||||
void strip(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
* \see strip
|
||||
*/
|
||||
void remove(int tags = AllTags);
|
||||
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
void scan();
|
||||
long findAPE();
|
||||
long findID3v1();
|
||||
long findID3v2();
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
140
Frameworks/TagLib/taglib/taglib/mpc/mpcproperties.cpp
Normal file
140
Frameworks/TagLib/taglib/taglib/mpc/mpcproperties.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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 "mpcproperties.h"
|
||||
#include "mpcfile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MPC::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) :
|
||||
data(d),
|
||||
streamLength(length),
|
||||
style(s),
|
||||
version(0),
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
channels(0) {}
|
||||
|
||||
ByteVector data;
|
||||
long streamLength;
|
||||
ReadStyle style;
|
||||
int version;
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate(data, streamLength, style);
|
||||
read();
|
||||
}
|
||||
|
||||
MPC::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int MPC::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int MPC::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int MPC::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int MPC::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int MPC::Properties::mpcVersion() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 };
|
||||
|
||||
void MPC::Properties::read()
|
||||
{
|
||||
if(!d->data.startsWith("MP+"))
|
||||
return;
|
||||
|
||||
d->version = d->data[3] & 15;
|
||||
|
||||
unsigned int frames;
|
||||
|
||||
if(d->version >= 7) {
|
||||
frames = d->data.mid(4, 4).toUInt(false);
|
||||
|
||||
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(d->data.mid(8, 4).toUInt(false)));
|
||||
d->sampleRate = sftable[flags[17] * 2 + flags[16]];
|
||||
d->channels = 2;
|
||||
}
|
||||
else {
|
||||
uint headerData = d->data.mid(0, 4).toUInt(false);
|
||||
|
||||
d->bitrate = (headerData >> 23) & 0x01ff;
|
||||
d->version = (headerData >> 11) & 0x03ff;
|
||||
d->sampleRate = 44100;
|
||||
d->channels = 2;
|
||||
|
||||
if(d->version >= 5)
|
||||
frames = d->data.mid(4, 4).toUInt(false);
|
||||
else
|
||||
frames = d->data.mid(6, 2).toUInt(false);
|
||||
}
|
||||
|
||||
uint samples = frames * 1152 - 576;
|
||||
|
||||
d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0;
|
||||
|
||||
if(!d->bitrate)
|
||||
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
|
||||
}
|
85
Frameworks/TagLib/taglib/taglib/mpc/mpcproperties.h
Normal file
85
Frameworks/TagLib/taglib/taglib/mpc/mpcproperties.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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.
|
||||
*/
|
||||
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this MPC::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the version of the bitstream (SV4-SV7)
|
||||
*/
|
||||
int mpcVersion() const;
|
||||
|
||||
private:
|
||||
Properties(const Properties &);
|
||||
Properties &operator=(const Properties &);
|
||||
|
||||
void read();
|
||||
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
219
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1genres.cpp
Normal file
219
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1genres.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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];
|
||||
return String::null;
|
||||
}
|
||||
|
||||
int ID3v1::genreIndex(const String &name)
|
||||
{
|
||||
if(genreMap().contains(name))
|
||||
return genreMap()[name];
|
||||
return 255;
|
||||
}
|
66
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1genres.h
Normal file
66
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1genres.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 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
|
284
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.cpp
Normal file
284
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
};
|
||||
|
||||
const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = new StringHandler;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// StringHandler implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
String ID3v1::StringHandler::parse(const ByteVector &data) const
|
||||
{
|
||||
return String(data, String::Latin1).stripWhiteSpace();
|
||||
}
|
||||
|
||||
ByteVector ID3v1::StringHandler::render(const String &s) const
|
||||
{
|
||||
if(!s.isLatin1())
|
||||
{
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
return s.data(String::Latin1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ID3v1::Tag::Tag() : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->file = file;
|
||||
d->tagOffset = tagOffset;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
ID3v1::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(fileIdentifier());
|
||||
data.append(TagPrivate::stringHandler->render(d->title).resize(30));
|
||||
data.append(TagPrivate::stringHandler->render(d->artist).resize(30));
|
||||
data.append(TagPrivate::stringHandler->render(d->album).resize(30));
|
||||
data.append(TagPrivate::stringHandler->render(d->year).resize(4));
|
||||
data.append(TagPrivate::stringHandler->render(d->comment).resize(28));
|
||||
data.append(char(0));
|
||||
data.append(char(d->track));
|
||||
data.append(char(d->genre));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("TAG");
|
||||
}
|
||||
|
||||
String ID3v1::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::album() const
|
||||
{
|
||||
return d->album;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::genre() const
|
||||
{
|
||||
return ID3v1::genre(d->genre);
|
||||
}
|
||||
|
||||
TagLib::uint ID3v1::Tag::year() const
|
||||
{
|
||||
return d->year.toInt();
|
||||
}
|
||||
|
||||
TagLib::uint ID3v1::Tag::track() const
|
||||
{
|
||||
return d->track;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgAlbumGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgTrackGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgTrackPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTitle(const String &s)
|
||||
{
|
||||
d->title = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setArtist(const String &s)
|
||||
{
|
||||
d->artist = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setAlbum(const String &s)
|
||||
{
|
||||
d->album = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setComment(const String &s)
|
||||
{
|
||||
d->comment = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setGenre(const String &s)
|
||||
{
|
||||
d->genre = ID3v1::genreIndex(s);
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setYear(uint i)
|
||||
{
|
||||
d->year = i > 0 ? String::number(i) : String::null;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTrack(uint i)
|
||||
{
|
||||
d->track = i < 256 ? i : 0;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setStringHandler(const StringHandler *handler)
|
||||
{
|
||||
delete TagPrivate::stringHandler;
|
||||
TagPrivate::stringHandler = handler;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGAlbumGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGAlbumPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGTrackGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGTrackPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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]);
|
||||
}
|
189
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.h
Normal file
189
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.h
Normal file
|
@ -0,0 +1,189 @@
|
|||
/***************************************************************************
|
||||
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.
|
||||
|
||||
/*!
|
||||
* Decode a string from \a data. The default implementation assumes that
|
||||
* \a data is an ISO-8859-1 (Latin1) character array.
|
||||
*/
|
||||
virtual String parse(const ByteVector &data) const;
|
||||
|
||||
/*!
|
||||
* Encode a ByteVector with the data from \a s. The default implementation
|
||||
* assumes that \a s is an ISO-8859-1 (Latin1) string. If the string is
|
||||
* does not conform to ISO-8859-1, no value is written.
|
||||
*
|
||||
* \warning It is recommended that you <b>not</b> override this method, but
|
||||
* instead do not write an ID3v1 tag in the case that the data is not
|
||||
* ISO-8859-1.
|
||||
*/
|
||||
virtual ByteVector render(const String &s) const;
|
||||
};
|
||||
|
||||
//! The main class in the ID3v1 implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of the ID3v1 format. ID3v1 is both the simplist
|
||||
* and most common of tag formats but is rather limited. Because of its
|
||||
* pervasiveness and the way that applications have been written around the
|
||||
* fields that it provides, the generic TagLib::Tag API is a mirror of what is
|
||||
* provided by ID3v1.
|
||||
*
|
||||
* ID3v1 tags should generally only contain Latin1 information. However because
|
||||
* many applications do not follow this rule there is now support for overriding
|
||||
* the ID3v1 string handling using the ID3v1::StringHandler class. Please see
|
||||
* the documentation for that class for more information.
|
||||
*
|
||||
* \see StringHandler
|
||||
*
|
||||
* \note Most fields are truncated to a maximum of 28-30 bytes. The
|
||||
* truncation happens automatically when the tag is rendered.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Create an ID3v1 tag with default values.
|
||||
*/
|
||||
Tag();
|
||||
|
||||
/*!
|
||||
* Create an ID3v1 tag and parse the data in \a file starting at
|
||||
* \a tagOffset.
|
||||
*/
|
||||
Tag(File *file, long tagOffset);
|
||||
|
||||
/*!
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Renders the in memory values to a ByteVector suitable for writing to
|
||||
* the file.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns the string "TAG" suitable for usage in locating the tag in a
|
||||
* file.
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual String title() const;
|
||||
virtual String artist() const;
|
||||
virtual String album() const;
|
||||
virtual String comment() const;
|
||||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() 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 void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
/*!
|
||||
* Sets the string handler that decides how the ID3v1 data will be
|
||||
* converted to and from binary data.
|
||||
*
|
||||
* \see StringHandler
|
||||
*/
|
||||
static void setStringHandler(const StringHandler *handler);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
void read();
|
||||
/*!
|
||||
* Pareses the body of the tag in \a data.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
private:
|
||||
Tag(const Tag &);
|
||||
Tag &operator=(const Tag &);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,222 @@
|
|||
/***************************************************************************
|
||||
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 = checkEncoding(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);
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
/***************************************************************************
|
||||
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
|
|
@ -0,0 +1,178 @@
|
|||
/***************************************************************************
|
||||
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"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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 = checkEncoding(d->description, encoding);
|
||||
encoding = checkEncoding(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));
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/***************************************************************************
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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
|
|
@ -0,0 +1,176 @@
|
|||
/***************************************************************************
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
/***************************************************************************
|
||||
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
|
|
@ -0,0 +1,236 @@
|
|||
/***************************************************************************
|
||||
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.mid(pos, 2).toShort();
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/***************************************************************************
|
||||
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
|
|
@ -0,0 +1,271 @@
|
|||
/***************************************************************************
|
||||
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"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class TextIdentificationFrame::TextIdentificationFramePrivate
|
||||
{
|
||||
public:
|
||||
TextIdentificationFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
StringList fieldList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) :
|
||||
Frame(type)
|
||||
{
|
||||
d = new TextIdentificationFramePrivate;
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
|
||||
Frame(data)
|
||||
{
|
||||
d = new TextIdentificationFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
TextIdentificationFrame::~TextIdentificationFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const StringList &l)
|
||||
{
|
||||
d->fieldList = l;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const String &s)
|
||||
{
|
||||
d->fieldList = s;
|
||||
}
|
||||
|
||||
String TextIdentificationFrame::toString() const
|
||||
{
|
||||
return d->fieldList.toString();
|
||||
}
|
||||
|
||||
StringList TextIdentificationFrame::fieldList() const
|
||||
{
|
||||
return d->fieldList;
|
||||
}
|
||||
|
||||
String::Type TextIdentificationFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TextIdentificationFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
// 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()) {
|
||||
String s(*it, d->textEncoding);
|
||||
d->fieldList.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector TextIdentificationFrame::renderFields() const
|
||||
{
|
||||
String::Type encoding = checkEncoding(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));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
/***************************************************************************
|
||||
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 "taglib_export.h"
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class Tag;
|
||||
|
||||
//! An ID3v2 text identification frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of the most common type of ID3v2 frame -- text
|
||||
* identification frames. There are a number of variations on this. Those
|
||||
* enumerated in the ID3v2.4 standard are:
|
||||
*
|
||||
* <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);
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
TextIdentificationFrame(const ByteVector &data, Header *h);
|
||||
|
||||
private:
|
||||
TextIdentificationFrame(const TextIdentificationFrame &);
|
||||
TextIdentificationFrame &operator=(const TextIdentificationFrame &);
|
||||
|
||||
class TextIdentificationFramePrivate;
|
||||
TextIdentificationFramePrivate *d;
|
||||
};
|
||||
|
||||
/*!
|
||||
* This is a specialization of text identification frames that allows for
|
||||
* user defined entries. Each entry has a description in addition to the
|
||||
* normal list of fields that a text identification frame has.
|
||||
*
|
||||
* This description identifies the frame and must be unique.
|
||||
*/
|
||||
|
||||
//! An ID3v2 custom text identification frame implementationx
|
||||
|
||||
class 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);
|
||||
|
||||
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);
|
||||
|
||||
/*!
|
||||
* 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
|
|
@ -0,0 +1,118 @@
|
|||
/***************************************************************************
|
||||
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 <tdebug.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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame &);
|
||||
UniqueFileIdentifierFrame &operator=(UniqueFileIdentifierFrame &);
|
||||
|
||||
UniqueFileIdentifierFrame(const ByteVector &data, Header *h);
|
||||
|
||||
class UniqueFileIdentifierFramePrivate;
|
||||
UniqueFileIdentifierFramePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,84 @@
|
|||
/***************************************************************************
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/***************************************************************************
|
||||
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
|
|
@ -0,0 +1,162 @@
|
|||
/***************************************************************************
|
||||
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 <tdebug.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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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) {
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/***************************************************************************
|
||||
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);
|
||||
|
||||
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
|
|
@ -0,0 +1,192 @@
|
|||
/***************************************************************************
|
||||
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 <tdebug.h>
|
||||
#include <tstringlist.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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = checkEncoding(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));
|
||||
}
|
172
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/frames/urllinkframe.h
Normal file
172
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/frames/urllinkframe.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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
|
1660
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2.2.0.txt
Normal file
1660
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2.2.0.txt
Normal file
File diff suppressed because it is too large
Load diff
2022
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2.3.0.txt
Normal file
2022
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2.3.0.txt
Normal file
File diff suppressed because it is too large
Load diff
1734
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2.4.0-frames.txt
Normal file
1734
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2.4.0-frames.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,733 @@
|
|||
|
||||
Informal standard M. Nilsson
|
||||
Document: id3v2.4.0-structure.txt 16 September 2001
|
||||
|
||||
|
||||
ID3 tag version 2.4.0 - Main Structure
|
||||
|
||||
Status of this document
|
||||
|
||||
This document is an informal standard and replaces the ID3v2.3.0
|
||||
standard [ID3v2]. A formal standard will use another revision number
|
||||
even if the content is identical to document. The contents in this
|
||||
document may change for clarifications but never for added or altered
|
||||
functionallity.
|
||||
|
||||
Distribution of this document is unlimited.
|
||||
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes the main structure of ID3v2.4.0, which is a
|
||||
revised version of the ID3v2 informal standard [ID3v2] version
|
||||
2.3.0. The ID3v2 offers a flexible way of storing audio meta
|
||||
information within the audio file itself. The information may be
|
||||
technical information, such as equalisation curves, as well as
|
||||
title, performer, copyright etc.
|
||||
|
||||
ID3v2.4.0 is meant to be as close as possible to ID3v2.3.0 in order
|
||||
to allow for implementations to be revised as easily as possible.
|
||||
|
||||
|
||||
1. Table of contents
|
||||
|
||||
Status of this document
|
||||
Abstract
|
||||
1. Table of contents
|
||||
2. Conventions in this document
|
||||
2. Standard overview
|
||||
3. ID3v2 overview
|
||||
3.1. ID3v2 header
|
||||
3.2. ID3v2 extended header
|
||||
3.3. Padding
|
||||
3.4. ID3v2 footer
|
||||
4. ID3v2 frames overview
|
||||
4.1. Frame header flags
|
||||
4.1.1. Frame status flags
|
||||
4.1.2. Frame format flags
|
||||
5. Tag location
|
||||
6. Unsynchronisation
|
||||
6.1. The unsynchronisation scheme
|
||||
6.2. Synchsafe integers
|
||||
7. Copyright
|
||||
8. References
|
||||
9. Author's Address
|
||||
|
||||
|
||||
2. Conventions in this document
|
||||
|
||||
Text within "" is a text string exactly as it appears in a tag.
|
||||
Numbers preceded with $ are hexadecimal and numbers preceded with %
|
||||
are binary. $xx is used to indicate a byte with unknown content. %x
|
||||
is used to indicate a bit with unknown content. The most significant
|
||||
bit (MSB) of a byte is called 'bit 7' and the least significant bit
|
||||
(LSB) is called 'bit 0'.
|
||||
|
||||
A tag is the whole tag described in this document. A frame is a block
|
||||
of information in the tag. The tag consists of a header, frames and
|
||||
optional padding. A field is a piece of information; one value, a
|
||||
string etc. A numeric string is a string that consists of the
|
||||
characters "0123456789" only.
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [KEYWORDS].
|
||||
|
||||
|
||||
3. ID3v2 overview
|
||||
|
||||
ID3v2 is a general tagging format for audio, which makes it possible
|
||||
to store meta data about the audio inside the audio file itself. The
|
||||
ID3 tag described in this document is mainly targeted at files
|
||||
encoded with MPEG-1/2 layer I, MPEG-1/2 layer II, MPEG-1/2 layer III
|
||||
and MPEG-2.5, but may work with other types of encoded audio or as a
|
||||
stand alone format for audio meta data.
|
||||
|
||||
ID3v2 is designed to be as flexible and expandable as possible to
|
||||
meet new meta information needs that might arise. To achieve that
|
||||
ID3v2 is constructed as a container for several information blocks,
|
||||
called frames, whose format need not be known to the software that
|
||||
encounters them. At the start of every frame is an unique and
|
||||
predefined identifier, a size descriptor that allows software to skip
|
||||
unknown frames and a flags field. The flags describes encoding
|
||||
details and if the frame should remain in the tag, should it be
|
||||
unknown to the software, if the file is altered.
|
||||
|
||||
The bitorder in ID3v2 is most significant bit first (MSB). The
|
||||
byteorder in multibyte numbers is most significant byte first (e.g.
|
||||
$12345678 would be encoded $12 34 56 78), also known as big endian
|
||||
and network byte order.
|
||||
|
||||
Overall tag structure:
|
||||
|
||||
+-----------------------------+
|
||||
| Header (10 bytes) |
|
||||
+-----------------------------+
|
||||
| Extended Header |
|
||||
| (variable length, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
| Frames (variable length) |
|
||||
+-----------------------------+
|
||||
| Padding |
|
||||
| (variable length, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
| Footer (10 bytes, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
|
||||
In general, padding and footer are mutually exclusive. See details in
|
||||
sections 3.3, 3.4 and 5.
|
||||
|
||||
|
||||
3.1. ID3v2 header
|
||||
|
||||
The first part of the ID3v2 tag is the 10 byte tag header, laid out
|
||||
as follows:
|
||||
|
||||
ID3v2/file identifier "ID3"
|
||||
ID3v2 version $04 00
|
||||
ID3v2 flags %abcd0000
|
||||
ID3v2 size 4 * %0xxxxxxx
|
||||
|
||||
The first three bytes of the tag are always "ID3", to indicate that
|
||||
this is an ID3v2 tag, directly followed by the two version bytes. The
|
||||
first byte of ID3v2 version is its major version, while the second
|
||||
byte is its revision number. In this case this is ID3v2.4.0. All
|
||||
revisions are backwards compatible while major versions are not. If
|
||||
software with ID3v2.4.0 and below support should encounter version
|
||||
five or higher it should simply ignore the whole tag. Version or
|
||||
revision will never be $FF.
|
||||
|
||||
The version is followed by the ID3v2 flags field, of which currently
|
||||
four flags are used.
|
||||
|
||||
|
||||
a - Unsynchronisation
|
||||
|
||||
Bit 7 in the 'ID3v2 flags' indicates whether or not
|
||||
unsynchronisation is applied on all frames (see section 6.1 for
|
||||
details); a set bit indicates usage.
|
||||
|
||||
|
||||
b - Extended header
|
||||
|
||||
The second bit (bit 6) indicates whether or not the header is
|
||||
followed by an extended header. The extended header is described in
|
||||
section 3.2. A set bit indicates the presence of an extended
|
||||
header.
|
||||
|
||||
|
||||
c - Experimental indicator
|
||||
|
||||
The third bit (bit 5) is used as an 'experimental indicator'. This
|
||||
flag SHALL always be set when the tag is in an experimental stage.
|
||||
|
||||
|
||||
d - Footer present
|
||||
|
||||
Bit 4 indicates that a footer (section 3.4) is present at the very
|
||||
end of the tag. A set bit indicates the presence of a footer.
|
||||
|
||||
|
||||
All the other flags MUST be cleared. If one of these undefined flags
|
||||
are set, the tag might not be readable for a parser that does not
|
||||
know the flags function.
|
||||
|
||||
The ID3v2 tag size is stored as a 32 bit synchsafe integer (section
|
||||
6.2), making a total of 28 effective bits (representing up to 256MB).
|
||||
|
||||
The ID3v2 tag size is the sum of the byte length of the extended
|
||||
header, the padding and the frames after unsynchronisation. If a
|
||||
footer is present this equals to ('total size' - 20) bytes, otherwise
|
||||
('total size' - 10) bytes.
|
||||
|
||||
An ID3v2 tag can be detected with the following pattern:
|
||||
$49 44 33 yy yy xx zz zz zz zz
|
||||
Where yy is less than $FF, xx is the 'flags' byte and zz is less than
|
||||
$80.
|
||||
|
||||
|
||||
3.2. Extended header
|
||||
|
||||
The extended header contains information that can provide further
|
||||
insight in the structure of the tag, but is not vital to the correct
|
||||
parsing of the tag information; hence the extended header is
|
||||
optional.
|
||||
|
||||
Extended header size 4 * %0xxxxxxx
|
||||
Number of flag bytes $01
|
||||
Extended Flags $xx
|
||||
|
||||
Where the 'Extended header size' is the size of the whole extended
|
||||
header, stored as a 32 bit synchsafe integer. An extended header can
|
||||
thus never have a size of fewer than six bytes.
|
||||
|
||||
The extended flags field, with its size described by 'number of flag
|
||||
bytes', is defined as:
|
||||
|
||||
%0bcd0000
|
||||
|
||||
Each flag that is set in the extended header has data attached, which
|
||||
comes in the order in which the flags are encountered (i.e. the data
|
||||
for flag 'b' comes before the data for flag 'c'). Unset flags cannot
|
||||
have any attached data. All unknown flags MUST be unset and their
|
||||
corresponding data removed when a tag is modified.
|
||||
|
||||
Every set flag's data starts with a length byte, which contains a
|
||||
value between 0 and 127 ($00 - $7f), followed by data that has the
|
||||
field length indicated by the length byte. If a flag has no attached
|
||||
data, the value $00 is used as length byte.
|
||||
|
||||
|
||||
b - Tag is an update
|
||||
|
||||
If this flag is set, the present tag is an update of a tag found
|
||||
earlier in the present file or stream. If frames defined as unique
|
||||
are found in the present tag, they are to override any
|
||||
corresponding ones found in the earlier tag. This flag has no
|
||||
corresponding data.
|
||||
|
||||
Flag data length $00
|
||||
|
||||
c - CRC data present
|
||||
|
||||
If this flag is set, a CRC-32 [ISO-3309] data is included in the
|
||||
extended header. The CRC is calculated on all the data between the
|
||||
header and footer as indicated by the header's tag length field,
|
||||
minus the extended header. Note that this includes the padding (if
|
||||
there is any), but excludes the footer. The CRC-32 is stored as an
|
||||
35 bit synchsafe integer, leaving the upper four bits always
|
||||
zeroed.
|
||||
|
||||
Flag data length $05
|
||||
Total frame CRC 5 * %0xxxxxxx
|
||||
|
||||
d - Tag restrictions
|
||||
|
||||
For some applications it might be desired to restrict a tag in more
|
||||
ways than imposed by the ID3v2 specification. Note that the
|
||||
presence of these restrictions does not affect how the tag is
|
||||
decoded, merely how it was restricted before encoding. If this flag
|
||||
is set the tag is restricted as follows:
|
||||
|
||||
Flag data length $01
|
||||
Restrictions %ppqrrstt
|
||||
|
||||
p - Tag size restrictions
|
||||
|
||||
00 No more than 128 frames and 1 MB total tag size.
|
||||
01 No more than 64 frames and 128 KB total tag size.
|
||||
10 No more than 32 frames and 40 KB total tag size.
|
||||
11 No more than 32 frames and 4 KB total tag size.
|
||||
|
||||
q - Text encoding restrictions
|
||||
|
||||
0 No restrictions
|
||||
1 Strings are only encoded with ISO-8859-1 [ISO-8859-1] or
|
||||
UTF-8 [UTF-8].
|
||||
|
||||
r - Text fields size restrictions
|
||||
|
||||
00 No restrictions
|
||||
01 No string is longer than 1024 characters.
|
||||
10 No string is longer than 128 characters.
|
||||
11 No string is longer than 30 characters.
|
||||
|
||||
Note that nothing is said about how many bytes is used to
|
||||
represent those characters, since it is encoding dependent. If a
|
||||
text frame consists of more than one string, the sum of the
|
||||
strungs is restricted as stated.
|
||||
|
||||
s - Image encoding restrictions
|
||||
|
||||
0 No restrictions
|
||||
1 Images are encoded only with PNG [PNG] or JPEG [JFIF].
|
||||
|
||||
t - Image size restrictions
|
||||
|
||||
00 No restrictions
|
||||
01 All images are 256x256 pixels or smaller.
|
||||
10 All images are 64x64 pixels or smaller.
|
||||
11 All images are exactly 64x64 pixels, unless required
|
||||
otherwise.
|
||||
|
||||
|
||||
3.3. Padding
|
||||
|
||||
It is OPTIONAL to include padding after the final frame (at the end
|
||||
of the ID3 tag), making the size of all the frames together smaller
|
||||
than the size given in the tag header. A possible purpose of this
|
||||
padding is to allow for adding a few additional frames or enlarge
|
||||
existing frames within the tag without having to rewrite the entire
|
||||
file. The value of the padding bytes must be $00. A tag MUST NOT have
|
||||
any padding between the frames or between the tag header and the
|
||||
frames. Furthermore it MUST NOT have any padding when a tag footer is
|
||||
added to the tag.
|
||||
|
||||
|
||||
3.4. ID3v2 footer
|
||||
|
||||
To speed up the process of locating an ID3v2 tag when searching from
|
||||
the end of a file, a footer can be added to the tag. It is REQUIRED
|
||||
to add a footer to an appended tag, i.e. a tag located after all
|
||||
audio data. The footer is a copy of the header, but with a different
|
||||
identifier.
|
||||
|
||||
ID3v2 identifier "3DI"
|
||||
ID3v2 version $04 00
|
||||
ID3v2 flags %abcd0000
|
||||
ID3v2 size 4 * %0xxxxxxx
|
||||
|
||||
|
||||
4. ID3v2 frame overview
|
||||
|
||||
All ID3v2 frames consists of one frame header followed by one or more
|
||||
fields containing the actual information. The header is always 10
|
||||
bytes and laid out as follows:
|
||||
|
||||
Frame ID $xx xx xx xx (four characters)
|
||||
Size 4 * %0xxxxxxx
|
||||
Flags $xx xx
|
||||
|
||||
The frame ID is made out of the characters capital A-Z and 0-9.
|
||||
Identifiers beginning with "X", "Y" and "Z" are for experimental
|
||||
frames and free for everyone to use, without the need to set the
|
||||
experimental bit in the tag header. Bear in mind that someone else
|
||||
might have used the same identifier as you. All other identifiers are
|
||||
either used or reserved for future use.
|
||||
|
||||
The frame ID is followed by a size descriptor containing the size of
|
||||
the data in the final frame, after encryption, compression and
|
||||
unsynchronisation. The size is excluding the frame header ('total
|
||||
frame size' - 10 bytes) and stored as a 32 bit synchsafe integer.
|
||||
|
||||
In the frame header the size descriptor is followed by two flag
|
||||
bytes. These flags are described in section 4.1.
|
||||
|
||||
There is no fixed order of the frames' appearance in the tag,
|
||||
although it is desired that the frames are arranged in order of
|
||||
significance concerning the recognition of the file. An example of
|
||||
such order: UFID, TIT2, MCDI, TRCK ...
|
||||
|
||||
A tag MUST contain at least one frame. A frame must be at least 1
|
||||
byte big, excluding the header.
|
||||
|
||||
If nothing else is said, strings, including numeric strings and URLs
|
||||
[URL], are represented as ISO-8859-1 [ISO-8859-1] characters in the
|
||||
range $20 - $FF. Such strings are represented in frame descriptions
|
||||
as <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
|
||||
Rydsvägen 246 C. 30
|
||||
SE-584 34 Linköping
|
||||
Sweden
|
||||
|
||||
Email: nilsson@id3.org
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/***************************************************************************
|
||||
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")
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/***************************************************************************
|
||||
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
|
60
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2footer.cpp
Normal file
60
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2footer.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
}
|
82
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2footer.h
Normal file
82
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2footer.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
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
|
549
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2frame.cpp
Normal file
549
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2frame.cpp
Normal file
|
@ -0,0 +1,549 @@
|
|||
/***************************************************************************
|
||||
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 HAVE_ZLIB
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class Frame::FramePrivate
|
||||
{
|
||||
public:
|
||||
FramePrivate() :
|
||||
header(0)
|
||||
{}
|
||||
|
||||
~FramePrivate()
|
||||
{
|
||||
delete header;
|
||||
}
|
||||
|
||||
Frame::Header *header;
|
||||
};
|
||||
|
||||
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 < '1' || *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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Frame::~Frame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector Frame::frameID() const
|
||||
{
|
||||
if(d->header)
|
||||
return d->header->frameID();
|
||||
else
|
||||
return ByteVector::null;
|
||||
}
|
||||
|
||||
TagLib::uint Frame::size() const
|
||||
{
|
||||
if(d->header)
|
||||
return d->header->frameSize();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Frame::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
void Frame::setText(const String &)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ByteVector Frame::render() const
|
||||
{
|
||||
ByteVector fieldData = renderFields();
|
||||
d->header->setFrameSize(fieldData.size());
|
||||
ByteVector headerData = d->header->render();
|
||||
|
||||
return headerData + fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Frame::Frame(const ByteVector &data)
|
||||
{
|
||||
d = new FramePrivate;
|
||||
d->header = new Header(data);
|
||||
}
|
||||
|
||||
Frame::Frame(Header *h)
|
||||
{
|
||||
d = new FramePrivate;
|
||||
d->header = h;
|
||||
}
|
||||
|
||||
Frame::Header *Frame::header() const
|
||||
{
|
||||
return d->header;
|
||||
}
|
||||
|
||||
void Frame::setHeader(Header *h, bool deleteCurrent)
|
||||
{
|
||||
if(deleteCurrent)
|
||||
delete d->header;
|
||||
|
||||
d->header = h;
|
||||
}
|
||||
|
||||
void Frame::parse(const ByteVector &data)
|
||||
{
|
||||
if(d->header)
|
||||
d->header->setData(data);
|
||||
else
|
||||
d->header = new Header(data);
|
||||
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
ByteVector Frame::fieldData(const ByteVector &frameData) const
|
||||
{
|
||||
uint headerSize = Header::size(d->header->version());
|
||||
|
||||
uint frameDataOffset = headerSize;
|
||||
uint frameDataLength = size();
|
||||
|
||||
if(d->header->compression() || d->header->dataLengthIndicator()) {
|
||||
frameDataLength = 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 = String(data.mid(*position, end - *position), encoding);
|
||||
|
||||
*position = end + delimiter.size();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding) // static
|
||||
{
|
||||
if(encoding != String::Latin1)
|
||||
return encoding;
|
||||
|
||||
for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
|
||||
if(!(*it).isLatin1()) {
|
||||
debug("Frame::checkEncoding() -- Rendering using UTF8.");
|
||||
return String::UTF8;
|
||||
}
|
||||
}
|
||||
|
||||
return String::Latin1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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.mid(3, 3).toUInt();
|
||||
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
// ID3v2.3
|
||||
|
||||
if(data.size() < 4) {
|
||||
debug("You must at least specify a frame ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the frame ID -- the first four bytes
|
||||
|
||||
d->frameID = data.mid(0, 4);
|
||||
|
||||
// If the full header information was not passed in, do not continue to the
|
||||
// steps to parse the frame size and flags.
|
||||
|
||||
if(data.size() < 10) {
|
||||
d->frameSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the size -- the frame size is the four bytes starting at byte four in
|
||||
// the frame header (structure 4)
|
||||
|
||||
d->frameSize = data.mid(4, 4).toUInt();
|
||||
|
||||
{ // read the first byte of flags
|
||||
std::bitset<8> flags(data[8]);
|
||||
d->tagAlterPreservation = flags[7]; // (structure 3.3.1.a)
|
||||
d->fileAlterPreservation = flags[6]; // (structure 3.3.1.b)
|
||||
d->readOnly = flags[5]; // (structure 3.3.1.c)
|
||||
}
|
||||
|
||||
{ // read the second byte of flags
|
||||
std::bitset<8> flags(data[9]);
|
||||
d->compression = flags[7]; // (structure 3.3.1.i)
|
||||
d->encryption = flags[6]; // (structure 3.3.1.j)
|
||||
d->groupingIdentity = flags[5]; // (structure 3.3.1.k)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
default:
|
||||
{
|
||||
// ID3v2.4
|
||||
|
||||
if(data.size() < 4) {
|
||||
debug("You must at least specify a frame ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the frame ID -- the first four bytes
|
||||
|
||||
d->frameID = data.mid(0, 4);
|
||||
|
||||
// If the full header information was not passed in, do not continue to the
|
||||
// steps to parse the frame size and flags.
|
||||
|
||||
if(data.size() < 10) {
|
||||
d->frameSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the size -- the frame size is the four bytes starting at byte four in
|
||||
// the frame header (structure 4)
|
||||
|
||||
d->frameSize = SynchData::toUInt(data.mid(4, 4));
|
||||
#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.mid(4, 4).toUInt();
|
||||
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;
|
||||
}
|
||||
|
||||
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 + SynchData::fromUInt(d->frameSize) + flags;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
bool Frame::Header::frameAlterPreservation() const
|
||||
{
|
||||
return fileAlterPreservation();
|
||||
}
|
414
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2frame.h
Normal file
414
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2frame.h
Normal file
|
@ -0,0 +1,414 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
|
||||
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:
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
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.
|
||||
*/
|
||||
static String::Type checkEncoding(const StringList &fields,
|
||||
String::Type encoding);
|
||||
|
||||
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).
|
||||
*/
|
||||
uint version() const;
|
||||
|
||||
/*!
|
||||
* Returns the size of the frame header in bytes.
|
||||
*
|
||||
* \deprecated Please use the version of this method that accepts a
|
||||
* version. This is only accurate for ID3v2.3 and ID3v2.4. This will be
|
||||
* removed in the next binary incompatible release (2.0) and will be
|
||||
* replaced with a non-static method that checks the frame version.
|
||||
*/
|
||||
static uint size();
|
||||
|
||||
/*!
|
||||
* Returns the size of the frame header in bytes for the ID3v2 version
|
||||
* that's given.
|
||||
*
|
||||
* \deprecated Please see the explanation in the version above.
|
||||
*/
|
||||
static uint size(uint version);
|
||||
|
||||
/*!
|
||||
* Returns true if the flag for tag alter preservation is set.
|
||||
*
|
||||
* 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
|
433
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp
Normal file
433
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp
Normal file
|
@ -0,0 +1,433 @@
|
|||
/***************************************************************************
|
||||
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 HAVE_ZLIB
|
||||
#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"
|
||||
|
||||
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 = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FrameFactory *FrameFactory::instance()
|
||||
{
|
||||
if(!factory)
|
||||
factory = new FrameFactory;
|
||||
return factory;
|
||||
}
|
||||
|
||||
Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const
|
||||
{
|
||||
return createFrame(data, uint(synchSafeInts ? 4 : 3));
|
||||
}
|
||||
|
||||
Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
|
||||
if( (*it < 'A' || *it > 'Z') && (*it < '1' || *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 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);
|
||||
|
||||
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("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("TSS", "TSSE", header);
|
||||
convertFrame("TT1", "TIT1", header);
|
||||
convertFrame("TT2", "TIT2", header);
|
||||
convertFrame("TT3", "TIT3", header);
|
||||
convertFrame("TXT", "TOLY", header);
|
||||
convertFrame("TXX", "TXXX", header);
|
||||
convertFrame("TYE", "TDRC", header);
|
||||
convertFrame("UFI", "UFID", header);
|
||||
convertFrame("ULT", "USLT", header);
|
||||
convertFrame("WAF", "WOAF", header);
|
||||
convertFrame("WAR", "WOAR", header);
|
||||
convertFrame("WAS", "WOAS", header);
|
||||
convertFrame("WCM", "WCOM", header);
|
||||
convertFrame("WCP", "WCOP", header);
|
||||
convertFrame("WPB", "WPUB", header);
|
||||
convertFrame("WXX", "WXXX", header);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // ID3v2.3
|
||||
{
|
||||
if(frameID == "EQUA" ||
|
||||
frameID == "RVAD" ||
|
||||
frameID == "TIME" ||
|
||||
frameID == "TRDA" ||
|
||||
frameID == "TSIZ" ||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
}
|
167
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2framefactory.h
Normal file
167
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2framefactory.h
Normal file
|
@ -0,0 +1,167 @@
|
|||
/***************************************************************************
|
||||
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. In most cases this will never be called (as
|
||||
* is typical of singletons).
|
||||
*/
|
||||
virtual ~FrameFactory();
|
||||
|
||||
/*!
|
||||
* This method checks for compliance to the current ID3v2 standard (2.4)
|
||||
* and does nothing in the common case. However if a frame is found that
|
||||
* is not compatible with the current standard, this method either updates
|
||||
* the frame or indicates that it should be discarded.
|
||||
*
|
||||
* This method with return true (with or without changes to the frame) if
|
||||
* this frame should be kept or false if it should be discarded.
|
||||
*
|
||||
* See the id3v2.4.0-changes.txt document for further information.
|
||||
*/
|
||||
virtual bool updateFrame(Frame::Header *header) const;
|
||||
|
||||
private:
|
||||
FrameFactory(const FrameFactory &);
|
||||
FrameFactory &operator=(const FrameFactory &);
|
||||
|
||||
/*!
|
||||
* This method is used internally to convert a frame from ID \a from to ID
|
||||
* \a to. If the frame matches the \a from pattern and converts the frame
|
||||
* ID in the \a header or simply does nothing if the frame ID does not match.
|
||||
*/
|
||||
void convertFrame(const char *from, const char *to,
|
||||
Frame::Header *header) const;
|
||||
|
||||
void updateGenre(TextIdentificationFrame *frame) const;
|
||||
|
||||
static FrameFactory *factory;
|
||||
|
||||
class FrameFactoryPrivate;
|
||||
FrameFactoryPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
243
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2header.cpp
Normal file
243
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2header.cpp
Normal file
|
@ -0,0 +1,243 @@
|
|||
/***************************************************************************
|
||||
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 <ostream>
|
||||
#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(4));
|
||||
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")
|
||||
}
|
175
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2header.h
Normal file
175
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2header.h
Normal file
|
@ -0,0 +1,175 @@
|
|||
/***************************************************************************
|
||||
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
|
|
@ -0,0 +1,77 @@
|
|||
/***************************************************************************
|
||||
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 <ostream>
|
||||
|
||||
#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.
|
||||
sum = (data.size() > 4) ? data.mid(0, 4).toUInt() : data.toUInt();
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
70
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2synchdata.h
Normal file
70
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2synchdata.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/***************************************************************************
|
||||
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
|
554
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.cpp
Normal file
554
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.cpp
Normal file
|
@ -0,0 +1,554 @@
|
|||
/***************************************************************************
|
||||
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 <tdebug.h>
|
||||
|
||||
#include "id3v2tag.h"
|
||||
#include "id3v2header.h"
|
||||
#include "id3v2extendedheader.h"
|
||||
#include "id3v2footer.h"
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
#include "id3v1genres.h"
|
||||
|
||||
#include "frames/textidentificationframe.h"
|
||||
#include "frames/commentsframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class ID3v2::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() : file(0), tagOffset(-1), extendedHeader(0), footer(0), paddingSize(0)
|
||||
{
|
||||
frameList.setAutoDelete(true);
|
||||
}
|
||||
~TagPrivate()
|
||||
{
|
||||
delete extendedHeader;
|
||||
delete footer;
|
||||
}
|
||||
|
||||
File *file;
|
||||
long tagOffset;
|
||||
const FrameFactory *factory;
|
||||
|
||||
Header header;
|
||||
ExtendedHeader *extendedHeader;
|
||||
Footer *footer;
|
||||
|
||||
int paddingSize;
|
||||
|
||||
FrameListMap frameListMap;
|
||||
FrameList frameList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ID3v2::Tag::Tag() : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->factory = FrameFactory::instance();
|
||||
}
|
||||
|
||||
ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) :
|
||||
TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
|
||||
d->file = file;
|
||||
d->tagOffset = tagOffset;
|
||||
d->factory = factory;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
ID3v2::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
String ID3v2::Tag::title() const
|
||||
{
|
||||
if(!d->frameListMap["TIT2"].isEmpty())
|
||||
return d->frameListMap["TIT2"].front()->toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String ID3v2::Tag::artist() const
|
||||
{
|
||||
if(!d->frameListMap["TPE1"].isEmpty())
|
||||
return d->frameListMap["TPE1"].front()->toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String ID3v2::Tag::album() const
|
||||
{
|
||||
if(!d->frameListMap["TALB"].isEmpty())
|
||||
return d->frameListMap["TALB"].front()->toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String ID3v2::Tag::comment() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rg(const String &type) const
|
||||
{
|
||||
const FrameList &list = d->frameListMap["TXXX"];
|
||||
if (!list.isEmpty()) {
|
||||
for (FrameList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (static_cast<UserTextIdentificationFrame *>(*it)->description() == type) {
|
||||
return static_cast<UserTextIdentificationFrame *>(*it)->toString().toFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgAlbumGain() const
|
||||
{
|
||||
return rg("replaygain_album_gain");
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return rg("replaygain_album_peak");
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgTrackGain() const
|
||||
{
|
||||
return rg("replaygain_track_gain");
|
||||
}
|
||||
|
||||
float ID3v2::Tag::rgTrackPeak() const
|
||||
{
|
||||
return rg("replaygain_track_peak");
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRG(const String &type, float f, bool peak)
|
||||
{
|
||||
bool createdFrame = false;
|
||||
UserTextIdentificationFrame * frame = NULL;
|
||||
FrameList &list = d->frameListMap["TXXX"];
|
||||
for (FrameList::Iterator it = list.begin(); it != list.end(); ++it) {
|
||||
if (static_cast<UserTextIdentificationFrame *>(*it)->description() == type) {
|
||||
frame = static_cast<UserTextIdentificationFrame*>(*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f == 0) {
|
||||
if (frame)
|
||||
removeFrame(frame);
|
||||
return;
|
||||
}
|
||||
if (frame == NULL) {
|
||||
frame = new UserTextIdentificationFrame;
|
||||
frame->setDescription(type);
|
||||
createdFrame = true;
|
||||
}
|
||||
frame->setText(String::number(f) + (peak ? "" : " dB"));
|
||||
if (createdFrame)
|
||||
addFrame(frame);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGAlbumGain(float f)
|
||||
{
|
||||
setRG("replaygain_album_gain", f, false);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGAlbumPeak(float f)
|
||||
{
|
||||
setRG("replaygain_album_peak", f, true);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGTrackGain(float f)
|
||||
{
|
||||
setRG("replaygain_track_gain", f, false);
|
||||
}
|
||||
|
||||
void ID3v2::Tag::setRGTrackPeak(float f)
|
||||
{
|
||||
setRG("replaygain_track_peak", f, true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ByteVector ID3v2::Tag::render() const
|
||||
{
|
||||
// We need to render the "tag data" first so that we have to correct size to
|
||||
// render in the tag's header. The "tag data" -- everything that is included
|
||||
// in ID3v2::Header::tagSize() -- includes the extended header, frames and
|
||||
// padding, but does not include the tag's header or footer.
|
||||
|
||||
ByteVector tagData;
|
||||
|
||||
// TODO: Render the extended header.
|
||||
|
||||
// Loop through the frames rendering them and adding them to the tagData.
|
||||
|
||||
for(FrameList::Iterator it = d->frameList.begin(); it != d->frameList.end(); it++) {
|
||||
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 tag size.
|
||||
d->header.setTagSize(tagData.size());
|
||||
|
||||
// TODO: This should eventually include d->footer->render().
|
||||
return d->header.render() + tagData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ID3v2::Tag::read()
|
||||
{
|
||||
if(d->file && d->file->isOpen()) {
|
||||
|
||||
d->file->seek(d->tagOffset);
|
||||
d->header.setData(d->file->readBlock(Header::size()));
|
||||
|
||||
// if the tag size is 0, then this is an invalid tag (tags must contain at
|
||||
// least one frame)
|
||||
|
||||
if(d->header.tagSize() == 0)
|
||||
return;
|
||||
|
||||
parse(d->file->readBlock(d->header.tagSize()));
|
||||
}
|
||||
}
|
||||
|
||||
void ID3v2::Tag::parse(const ByteVector &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);
|
||||
}
|
||||
}
|
312
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.h
Normal file
312
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.h
Normal file
|
@ -0,0 +1,312 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
|
||||
//! 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;
|
||||
|
||||
float rg(const String &type) const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() 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);
|
||||
|
||||
void setRG(const String &type, float f, bool peak);
|
||||
virtual void setRGAlbumGain(float f);
|
||||
virtual void setRGAlbumPeak(float f);
|
||||
virtual void setRGTrackGain(float f);
|
||||
virtual void setRGTrackPeak(float f);
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's header.
|
||||
*/
|
||||
Header *header() const;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's extended header or null if there is no
|
||||
* extended header.
|
||||
*/
|
||||
ExtendedHeader *extendedHeader() const;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's footer or null if there is no footer.
|
||||
*
|
||||
* \deprecated I don't see any reason to keep this around since there's
|
||||
* nothing useful to be retrieved from the footer, but well, again, I'm
|
||||
* prone to change my mind, so this gets to stay around until near a
|
||||
* release.
|
||||
*/
|
||||
Footer *footer() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the frame list map. This is an FrameListMap of
|
||||
* all of the frames in the tag.
|
||||
*
|
||||
* This is the most convenient structure for accessing the tag's frames.
|
||||
* Many frame types allow multiple instances of the same frame type so this
|
||||
* is a map of lists. In most cases however there will only be a single
|
||||
* frame of a certain type.
|
||||
*
|
||||
* Let's say for instance that you wanted to access the frame for total
|
||||
* beats per minute -- the TBPM frame.
|
||||
*
|
||||
* \code
|
||||
* TagLib::MPEG::File f("foo.mp3");
|
||||
*
|
||||
* // Check to make sure that it has an ID3v2 tag
|
||||
*
|
||||
* if(f.ID3v2Tag()) {
|
||||
*
|
||||
* // Get the list of frames for a specific frame type
|
||||
*
|
||||
* TagLib::ID3v2::FrameList l = f.ID3v2Tag()->frameListMap()["TBPM"];
|
||||
*
|
||||
* if(!l.isEmpty())
|
||||
* std::cout << l.front()->toString() << std::endl;
|
||||
* }
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addFrame() and removeFrame().
|
||||
*
|
||||
* \see frameList()
|
||||
*/
|
||||
const FrameListMap &frameListMap() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the frame list. This is an FrameList of all of
|
||||
* the frames in the tag in the order that they were parsed.
|
||||
*
|
||||
* This can be useful if for example you want iterate over the tag's frames
|
||||
* in the order that they occur in the tag.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use addFrame() and removeFrame().
|
||||
*/
|
||||
const FrameList &frameList() const;
|
||||
|
||||
/*!
|
||||
* Returns the frame list for frames with the id \a frameID or an empty
|
||||
* list if there are no frames of that type. This is just a convenience
|
||||
* and is equivalent to:
|
||||
*
|
||||
* \code
|
||||
* frameListMap()[frameID];
|
||||
* \endcode
|
||||
*
|
||||
* \see frameListMap()
|
||||
*/
|
||||
const FrameList &frameList(const ByteVector &frameID) const;
|
||||
|
||||
/*!
|
||||
* Add a frame to the tag. At this point the tag takes ownership of
|
||||
* the frame and will handle freeing its memory.
|
||||
*
|
||||
* \note Using this method will invalidate any pointers on the list
|
||||
* returned by frameList()
|
||||
*/
|
||||
void addFrame(Frame *frame);
|
||||
|
||||
/*!
|
||||
* Remove a frame from the tag. If \a del is true the frame's memory
|
||||
* will be freed; if it is false, it must be deleted by the user.
|
||||
*
|
||||
* \note Using this method will invalidate any pointers on the list
|
||||
* returned by frameList()
|
||||
*/
|
||||
void removeFrame(Frame *frame, bool del = true);
|
||||
|
||||
/*!
|
||||
* Remove all frames of type \a id from the tag and free their memory.
|
||||
*
|
||||
* \note Using this method will invalidate any pointers on the list
|
||||
* returned by frameList()
|
||||
*/
|
||||
void removeFrames(const ByteVector &id);
|
||||
|
||||
/*!
|
||||
* Render the tag back to binary data, suitable to be written to disk.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Reads data from the file specified in the constructor. It does basic
|
||||
* parsing of the data in the largest chunks. It partitions the tag into
|
||||
* the Header, the body of the tag (which contains the ExtendedHeader and
|
||||
* frames) and Footer.
|
||||
*/
|
||||
void read();
|
||||
|
||||
/*!
|
||||
* This is called by read to parse the body of the tag. It determines if an
|
||||
* extended header exists and adds frames to the FrameListMap.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Sets the value of the text frame with the Frame ID \a id to \a value.
|
||||
* If the frame does not exist, it is created.
|
||||
*/
|
||||
void setTextFrame(const ByteVector &id, const String &value);
|
||||
|
||||
private:
|
||||
Tag(const Tag &);
|
||||
Tag &operator=(const Tag &);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
593
Frameworks/TagLib/taglib/taglib/mpeg/mpegfile.cpp
Normal file
593
Frameworks/TagLib/taglib/taglib/mpeg/mpegfile.cpp
Normal file
|
@ -0,0 +1,593 @@
|
|||
/***************************************************************************
|
||||
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"
|
||||
|
||||
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()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *MPEG::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
MPEG::Properties *MPEG::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool MPEG::File::save()
|
||||
{
|
||||
return save(AllTags);
|
||||
}
|
||||
|
||||
bool MPEG::File::save(int tags)
|
||||
{
|
||||
return save(tags, true);
|
||||
}
|
||||
|
||||
bool MPEG::File::save(int tags, bool stripOthers)
|
||||
{
|
||||
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. Copy the values from the tag that
|
||||
// does exist into the new tag.
|
||||
|
||||
if((tags & ID3v2) && ID3v1Tag())
|
||||
Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false);
|
||||
|
||||
if((tags & ID3v1) && d->tag[ID3v2Index])
|
||||
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(), 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();
|
||||
d->APEFooterLocation = d->APELocation
|
||||
+ d->tag.access<APE::Tag>(APEIndex, false)->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());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
{
|
||||
if(uchar(byte) == 0xff)
|
||||
return false;
|
||||
|
||||
std::bitset<8> b(byte);
|
||||
|
||||
// check to see if the byte matches 111xxxxx
|
||||
return b.test(7) && b.test(6) && b.test(5);
|
||||
}
|
277
Frameworks/TagLib/taglib/taglib/mpeg/mpegfile.h
Normal file
277
Frameworks/TagLib/taglib/taglib/mpeg/mpegfile.h
Normal file
|
@ -0,0 +1,277 @@
|
|||
/***************************************************************************
|
||||
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 "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
|
||||
};
|
||||
|
||||
/*!
|
||||
* Contructs an MPEG file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \deprecated This constructor will be dropped in favor of the one below
|
||||
* in a future version.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an MPEG file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored. The frames will be created using
|
||||
* \a frameFactory.
|
||||
*/
|
||||
// BIC: merge with the above constructor
|
||||
File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to a tag that is the union of the ID3v2 and ID3v1
|
||||
* tags. The ID3v2 tag is given priority in reading the information -- if
|
||||
* requested information exists in both the ID3v2 tag and the ID3v1 tag,
|
||||
* the information from the ID3v2 tag will be returned.
|
||||
*
|
||||
* If you would like more granular control over the content of the tags,
|
||||
* with the concession of generality, use the tag-type specific calls.
|
||||
*
|
||||
* \note As this tag is not implemented as an ID3v2 tag or an ID3v1 tag,
|
||||
* but a union of the two this pointer may not be cast to the specific
|
||||
* tag types.
|
||||
*
|
||||
* \see ID3v1Tag()
|
||||
* \see ID3v2Tag()
|
||||
* \see APETag()
|
||||
*/
|
||||
virtual Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the MPEG::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file. If at least one tag -- ID3v1 or ID3v2 -- exists this
|
||||
* will duplicate its content into the other tag. This returns true
|
||||
* if saving was successful.
|
||||
*
|
||||
* If neither exists or if both tags are empty, this will strip the tags
|
||||
* from the file.
|
||||
*
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* If you would like more granular control over the content of the tags,
|
||||
* with the concession of generality, use paramaterized save call below.
|
||||
*
|
||||
* \see save(int tags)
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Save the file. This will attempt to save all of the tag types that are
|
||||
* specified by OR-ing together TagTypes values. The save() method above
|
||||
* uses AllTags. This returns true if saving was successful.
|
||||
*
|
||||
* This strips all tags not included in the mask, but does not modify them
|
||||
* in memory, so later calls to save() which make use of these tags will
|
||||
* remain valid. This also strips empty tags.
|
||||
*/
|
||||
bool save(int tags);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v2 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v2 tag. If \a create is true it will create
|
||||
* an ID3v2 tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v2::Tag *ID3v2Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <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.
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* an APE tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <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.
|
||||
*/
|
||||
APE::Tag *APETag(bool create = false);
|
||||
|
||||
/*!
|
||||
* This will strip the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it strips all tags. It returns true if the tags are
|
||||
* successfully stripped.
|
||||
*
|
||||
* This is equivalent to strip(tags, true)
|
||||
*
|
||||
* \note This will also invalidate pointers to the ID3 and APE tags
|
||||
* as their memory will be freed.
|
||||
*/
|
||||
bool strip(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* This will strip the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it strips all tags. It returns true if the tags are
|
||||
* successfully stripped.
|
||||
*
|
||||
* If \a freeMemory is true the ID3 and APE tags will be deleted and
|
||||
* pointers to them will be invalidated.
|
||||
*/
|
||||
// BIC: merge with the method above
|
||||
bool strip(int tags, bool freeMemory);
|
||||
|
||||
/*!
|
||||
* Set the ID3v2::FrameFactory to something other than the default.
|
||||
*
|
||||
* \see ID3v2FrameFactory
|
||||
*/
|
||||
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
|
||||
|
||||
/*!
|
||||
* Returns the position in the file of the first MPEG frame.
|
||||
*/
|
||||
long firstFrameOffset();
|
||||
|
||||
/*!
|
||||
* Returns the position in the file of the next MPEG frame,
|
||||
* using the current position as start
|
||||
*/
|
||||
long nextFrameOffset(long position);
|
||||
|
||||
/*!
|
||||
* Returns the position in the file of the previous MPEG frame,
|
||||
* using the current position as start
|
||||
*/
|
||||
long previousFrameOffset(long position);
|
||||
|
||||
/*!
|
||||
* Returns the position in the file of the last MPEG frame.
|
||||
*/
|
||||
long lastFrameOffset();
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
long findID3v2();
|
||||
long findID3v1();
|
||||
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
|
276
Frameworks/TagLib/taglib/taglib/mpeg/mpegheader.cpp
Normal file
276
Frameworks/TagLib/taglib/taglib/mpeg/mpegheader.cpp
Normal file
|
@ -0,0 +1,276 @@
|
|||
/***************************************************************************
|
||||
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 "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;
|
||||
}
|
166
Frameworks/TagLib/taglib/taglib/mpeg/mpegheader.h
Normal file
166
Frameworks/TagLib/taglib/taglib/mpeg/mpegheader.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/***************************************************************************
|
||||
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
|
254
Frameworks/TagLib/taglib/taglib/mpeg/mpegproperties.cpp
Normal file
254
Frameworks/TagLib/taglib/taglib/mpeg/mpegproperties.cpp
Normal file
|
@ -0,0 +1,254 @@
|
|||
/***************************************************************************
|
||||
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 ? 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();
|
||||
}
|
118
Frameworks/TagLib/taglib/taglib/mpeg/mpegproperties.h
Normal file
118
Frameworks/TagLib/taglib/taglib/mpeg/mpegproperties.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/***************************************************************************
|
||||
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
|
115
Frameworks/TagLib/taglib/taglib/mpeg/xingheader.cpp
Normal file
115
Frameworks/TagLib/taglib/taglib/mpeg/xingheader.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/***************************************************************************
|
||||
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.mid(8, 4).toUInt();
|
||||
d->size = data.mid(12, 4).toUInt();
|
||||
|
||||
d->valid = true;
|
||||
}
|
100
Frameworks/TagLib/taglib/taglib/mpeg/xingheader.h
Normal file
100
Frameworks/TagLib/taglib/taglib/mpeg/xingheader.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/***************************************************************************
|
||||
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
|
269
Frameworks/TagLib/taglib/taglib/ogg/flac/oggflacfile.cpp
Normal file
269
Frameworks/TagLib/taglib/taglib/ogg/flac/oggflacfile.cpp
Normal file
|
@ -0,0 +1,269 @@
|
|||
/***************************************************************************
|
||||
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 <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;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Ogg::FLAC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Ogg::XiphComment *Ogg::FLAC::File::tag() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
Properties *Ogg::FLAC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
|
||||
bool Ogg::FLAC::File::save()
|
||||
{
|
||||
d->xiphCommentData = d->comment->render(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();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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.mid(1, 3).toUInt();
|
||||
overhead += length;
|
||||
|
||||
// Sanity: First block should be the stream_info metadata
|
||||
|
||||
if(blockType != 0) {
|
||||
debug("Ogg::FLAC::File::scan() -- Invalid Ogg/FLAC stream");
|
||||
return;
|
||||
}
|
||||
|
||||
d->streamInfoData = metadataHeader.mid(4,length);
|
||||
|
||||
// Search through the remaining metadata
|
||||
|
||||
while(!lastBlock) {
|
||||
metadataHeader = packet(++ipacket);
|
||||
|
||||
if(metadataHeader.isNull())
|
||||
return;
|
||||
|
||||
header = metadataHeader.mid(0, 4);
|
||||
blockType = header[0] & 0x7f;
|
||||
lastBlock = (header[0] & 0x80) != 0;
|
||||
length = header.mid(1, 3).toUInt();
|
||||
overhead += length;
|
||||
|
||||
if(blockType == 1) {
|
||||
// debug("Ogg::FLAC::File::scan() -- Padding found");
|
||||
}
|
||||
else if(blockType == 4) {
|
||||
// debug("Ogg::FLAC::File::scan() -- Vorbis-comments found");
|
||||
d->xiphCommentData = metadataHeader.mid(4, length);
|
||||
d->hasXiphComment = true;
|
||||
d->commentPacket = ipacket;
|
||||
}
|
||||
else if(blockType > 5)
|
||||
debug("Ogg::FLAC::File::scan() -- Unknown metadata block");
|
||||
|
||||
}
|
||||
|
||||
// End of metadata, now comes the datastream
|
||||
d->streamStart = overhead;
|
||||
d->streamLength = File::length() - d->streamStart;
|
||||
|
||||
d->scanned = true;
|
||||
}
|
118
Frameworks/TagLib/taglib/taglib/ogg/flac/oggflacfile.h
Normal file
118
Frameworks/TagLib/taglib/taglib/ogg/flac/oggflacfile.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/***************************************************************************
|
||||
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:
|
||||
/*!
|
||||
* Contructs an Ogg/FLAC file from \a file. If \a readProperties is true
|
||||
* the file's audio properties will also be read using \a propertiesStyle.
|
||||
* If false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will always be a XiphComment.
|
||||
*/
|
||||
virtual XiphComment *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the FLAC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file. This will primarily save and update the XiphComment.
|
||||
* Returns true if the save is successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns the length of the audio-stream, used by FLAC::Properties for
|
||||
* calculating the bitrate.
|
||||
*/
|
||||
long streamLength();
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
void scan();
|
||||
ByteVector streamInfoData();
|
||||
ByteVector xiphCommentData();
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
} // namespace FLAC
|
||||
} // namespace Ogg
|
||||
} // namespace TagLib
|
||||
|
||||
#endif
|
427
Frameworks/TagLib/taglib/taglib/ogg/oggfile.cpp
Normal file
427
Frameworks/TagLib/taglib/taglib/ogg/oggfile.cpp
Normal file
|
@ -0,0 +1,427 @@
|
|||
/***************************************************************************
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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.");
|
||||
}
|
||||
}
|
||||
}
|
112
Frameworks/TagLib/taglib/taglib/ogg/oggfile.h
Normal file
112
Frameworks/TagLib/taglib/taglib/ogg/oggfile.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
/***************************************************************************
|
||||
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:
|
||||
/*!
|
||||
* Contructs an Ogg file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note This constructor is protected since Ogg::File shouldn't be
|
||||
* instantiated directly but rather should be used through the codec
|
||||
* specific subclasses.
|
||||
*/
|
||||
File(FileName file);
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
/*!
|
||||
* Reads the next page and updates the internal "current page" pointer.
|
||||
*/
|
||||
bool nextPage();
|
||||
void writePageGroup(const List<int> &group);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
340
Frameworks/TagLib/taglib/taglib/ogg/oggpage.cpp
Normal file
340
Frameworks/TagLib/taglib/taglib/ogg/oggpage.cpp
Normal file
|
@ -0,0 +1,340 @@
|
|||
/***************************************************************************
|
||||
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);
|
||||
}
|
||||
|
211
Frameworks/TagLib/taglib/taglib/ogg/oggpage.h
Normal file
211
Frameworks/TagLib/taglib/taglib/ogg/oggpage.h
Normal file
|
@ -0,0 +1,211 @@
|
|||
/***************************************************************************
|
||||
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
|
323
Frameworks/TagLib/taglib/taglib/ogg/oggpageheader.cpp
Normal file
323
Frameworks/TagLib/taglib/taglib/ogg/oggpageheader.cpp
Normal file
|
@ -0,0 +1,323 @@
|
|||
/***************************************************************************
|
||||
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.mid(6, 8).toLongLong(false);
|
||||
d->streamSerialNumber = data.mid(14, 4).toUInt(false);
|
||||
d->pageSequenceNumber = data.mid(18, 4).toUInt(false);
|
||||
|
||||
// Byte number 27 is the number of page segments, which is the only variable
|
||||
// length portion of the page header. After reading the number of page
|
||||
// segments we'll then read in the 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;
|
||||
}
|
232
Frameworks/TagLib/taglib/taglib/ogg/oggpageheader.h
Normal file
232
Frameworks/TagLib/taglib/taglib/ogg/oggpageheader.h
Normal file
|
@ -0,0 +1,232 @@
|
|||
/***************************************************************************
|
||||
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
|
112
Frameworks/TagLib/taglib/taglib/ogg/speex/speexfile.cpp
Normal file
112
Frameworks/TagLib/taglib/taglib/ogg/speex/speexfile.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
/***************************************************************************
|
||||
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 "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;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Speex::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Ogg::XiphComment *Speex::File::tag() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
99
Frameworks/TagLib/taglib/taglib/ogg/speex/speexfile.h
Normal file
99
Frameworks/TagLib/taglib/taglib/ogg/speex/speexfile.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/***************************************************************************
|
||||
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:
|
||||
/*!
|
||||
* Contructs a Speex file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the XiphComment for this file. XiphComment implements the tag
|
||||
* interface, so this serves as the reimplementation of
|
||||
* TagLib::File::tag().
|
||||
*/
|
||||
virtual Ogg::XiphComment *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the 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
|
170
Frameworks/TagLib/taglib/taglib/ogg/speex/speexproperties.cpp
Normal file
170
Frameworks/TagLib/taglib/taglib/ogg/speex/speexproperties.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
/***************************************************************************
|
||||
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);
|
||||
|
||||
int pos = 28;
|
||||
|
||||
// speex_version_id; /**< Version for Speex (for checking compatibility) */
|
||||
d->speexVersion = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
// header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */
|
||||
pos += 4;
|
||||
|
||||
// rate; /**< Sampling rate used */
|
||||
d->sampleRate = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
// mode; /**< Mode used (0 for narrowband, 1 for wideband) */
|
||||
d->mode = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
// mode_bitstream_version; /**< Version ID of the bit-stream */
|
||||
pos += 4;
|
||||
|
||||
// nb_channels; /**< Number of channels encoded */
|
||||
d->channels = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
// bitrate; /**< Bit-rate used */
|
||||
d->bitrate = data.mid(pos, 4).toUInt(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.mid(pos, 4).toUInt(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.");
|
||||
}
|
89
Frameworks/TagLib/taglib/taglib/ogg/speex/speexproperties.h
Normal file
89
Frameworks/TagLib/taglib/taglib/ogg/speex/speexproperties.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/***************************************************************************
|
||||
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
|
117
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisfile.cpp
Normal file
117
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisfile.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
/***************************************************************************
|
||||
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 "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;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
Vorbis::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Ogg::XiphComment *Vorbis::File::tag() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
Vorbis::Properties *Vorbis::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool Vorbis::File::save()
|
||||
{
|
||||
ByteVector v(vorbisCommentHeaderID);
|
||||
|
||||
if(!d->comment)
|
||||
d->comment = new Ogg::XiphComment;
|
||||
v.append(d->comment->render());
|
||||
|
||||
setPacket(1, v);
|
||||
|
||||
return Ogg::File::save();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Vorbis::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
{
|
||||
ByteVector commentHeaderData = packet(1);
|
||||
|
||||
if(commentHeaderData.mid(0, 7) != vorbisCommentHeaderID) {
|
||||
debug("Vorbis::File::read() - Could not find the Vorbis comment header.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
d->comment = new Ogg::XiphComment(commentHeaderData.mid(7));
|
||||
|
||||
if(readProperties)
|
||||
d->properties = new Properties(this, propertiesStyle);
|
||||
}
|
118
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisfile.h
Normal file
118
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisfile.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/***************************************************************************
|
||||
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:
|
||||
/*!
|
||||
* Contructs a Vorbis file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the XiphComment for this file. XiphComment implements the tag
|
||||
* interface, so this serves as the reimplementation of
|
||||
* TagLib::File::tag().
|
||||
*/
|
||||
virtual Ogg::XiphComment *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the Vorbis::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
virtual bool save();
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* To keep compatibility with the current version put Vorbis in the Ogg namespace
|
||||
* only in the docs and provide a typedef to make it work. In the next BIC
|
||||
* version this will be removed and it will only exist in the Ogg namespace.
|
||||
*/
|
||||
|
||||
#ifdef DOXYGEN
|
||||
}
|
||||
#else
|
||||
namespace Ogg { namespace Vorbis { typedef TagLib::Vorbis::File File; } }
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
183
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisproperties.cpp
Normal file
183
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisproperties.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
/***************************************************************************
|
||||
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);
|
||||
|
||||
int pos = 0;
|
||||
|
||||
if(data.mid(pos, 7) != vorbisSetupHeaderID) {
|
||||
debug("Vorbis::Properties::read() -- invalid Vorbis identification header");
|
||||
return;
|
||||
}
|
||||
|
||||
pos += 7;
|
||||
|
||||
d->vorbisVersion = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
d->channels = uchar(data[pos]);
|
||||
pos += 1;
|
||||
|
||||
d->sampleRate = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
d->bitrateMaximum = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
d->bitrateNominal = data.mid(pos, 4).toUInt(false);
|
||||
pos += 4;
|
||||
|
||||
d->bitrateMinimum = data.mid(pos, 4).toUInt(false);
|
||||
|
||||
// TODO: Later this should be only the "fast" mode.
|
||||
d->bitrate = d->bitrateNominal;
|
||||
|
||||
// Find the length of the file. See http://wiki.xiph.org/VorbisStreamLength/
|
||||
// for my notes on the topic.
|
||||
|
||||
const Ogg::PageHeader *first = d->file->firstPageHeader();
|
||||
const Ogg::PageHeader *last = d->file->lastPageHeader();
|
||||
|
||||
if(first && last) {
|
||||
long long start = first->absoluteGranularPosition();
|
||||
long long end = last->absoluteGranularPosition();
|
||||
|
||||
if(start >= 0 && end >= 0 && d->sampleRate > 0)
|
||||
d->length = (end - start) / (long long) d->sampleRate;
|
||||
else
|
||||
debug("Vorbis::Properties::read() -- Either the PCM values for the start or "
|
||||
"end of this file was incorrect or the sample rate is zero.");
|
||||
}
|
||||
else
|
||||
debug("Vorbis::Properties::read() -- Could not find valid first and last Ogg pages.");
|
||||
}
|
125
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisproperties.h
Normal file
125
Frameworks/TagLib/taglib/taglib/ogg/vorbis/vorbisproperties.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/***************************************************************************
|
||||
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
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue