Taglib 1.5
This commit is contained in:
parent
70b19e6cfa
commit
c391097b00
123 changed files with 30825 additions and 0 deletions
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!
|
481
Frameworks/TagLib/taglib/COPYING.LGPL
Normal file
481
Frameworks/TagLib/taglib/COPYING.LGPL
Normal file
|
@ -0,0 +1,481 @@
|
||||||
|
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA.
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the library GPL. It is
|
||||||
|
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Library General Public License, applies to some
|
||||||
|
specially designated Free Software Foundation software, and to any
|
||||||
|
other libraries whose authors decide to use it. You can use it for
|
||||||
|
your libraries, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if
|
||||||
|
you distribute copies of the library, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link a program with the library, you must provide
|
||||||
|
complete object files to the recipients so that they can relink them
|
||||||
|
with the library, after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
Our method of protecting your rights has two steps: (1) copyright
|
||||||
|
the library, and (2) offer you this license which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
Also, for each distributor's protection, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
library. If the library is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original
|
||||||
|
version, so that any problems introduced by others will not reflect on
|
||||||
|
the original authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that companies distributing free
|
||||||
|
software will individually obtain patent licenses, thus in effect
|
||||||
|
transforming the program into proprietary software. To prevent this,
|
||||||
|
we have made it clear that any patent must be licensed for everyone's
|
||||||
|
free use or not licensed at all.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the ordinary
|
||||||
|
GNU General Public License, which was designed for utility programs. This
|
||||||
|
license, the GNU Library General Public License, applies to certain
|
||||||
|
designated libraries. This license is quite different from the ordinary
|
||||||
|
one; be sure to read it in full, and don't assume that anything in it is
|
||||||
|
the same as in the ordinary license.
|
||||||
|
|
||||||
|
The reason we have a separate public license for some libraries is that
|
||||||
|
they blur the distinction we usually make between modifying or adding to a
|
||||||
|
program and simply using it. Linking a program with a library, without
|
||||||
|
changing the library, is in some sense simply using the library, and is
|
||||||
|
analogous to running a utility program or application program. However, in
|
||||||
|
a textual and legal sense, the linked executable is a combined work, a
|
||||||
|
derivative of the original library, and the ordinary General Public License
|
||||||
|
treats it as such.
|
||||||
|
|
||||||
|
Because of this blurred distinction, using the ordinary General
|
||||||
|
Public License for libraries did not effectively promote software
|
||||||
|
sharing, because most developers did not use the libraries. We
|
||||||
|
concluded that weaker conditions might promote sharing better.
|
||||||
|
|
||||||
|
However, unrestricted linking of non-free programs would deprive the
|
||||||
|
users of those programs of all benefit from the free status of the
|
||||||
|
libraries themselves. This Library General Public License is intended to
|
||||||
|
permit developers of non-free programs to use free libraries, while
|
||||||
|
preserving your freedom as a user of such programs to change the free
|
||||||
|
libraries that are incorporated in them. (We have not seen how to achieve
|
||||||
|
this as regards changes in header files, but we have achieved it as regards
|
||||||
|
changes in the actual functions of the Library.) The hope is that this
|
||||||
|
will lead to faster development of free libraries.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, while the latter only
|
||||||
|
works together with the library.
|
||||||
|
|
||||||
|
Note that it is possible for a library to be covered by the ordinary
|
||||||
|
General Public License rather than by this special one.
|
||||||
|
|
||||||
|
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library which
|
||||||
|
contains a notice placed by the copyright holder or other authorized
|
||||||
|
party saying it may be distributed under the terms of this Library
|
||||||
|
General Public License (also called "this License"). Each licensee is
|
||||||
|
addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also compile or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
c) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
d) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the source code distributed need not include anything that is normally
|
||||||
|
distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Library General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<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 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
470
Frameworks/TagLib/taglib/COPYING.MPL
Normal file
470
Frameworks/TagLib/taglib/COPYING.MPL
Normal file
|
@ -0,0 +1,470 @@
|
||||||
|
MOZILLA PUBLIC LICENSE
|
||||||
|
Version 1.1
|
||||||
|
|
||||||
|
---------------
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
1.0.1. "Commercial Use" means distribution or otherwise making the
|
||||||
|
Covered Code available to a third party.
|
||||||
|
|
||||||
|
1.1. "Contributor" means each entity that creates or contributes to
|
||||||
|
the creation of Modifications.
|
||||||
|
|
||||||
|
1.2. "Contributor Version" means the combination of the Original
|
||||||
|
Code, prior Modifications used by a Contributor, and the Modifications
|
||||||
|
made by that particular Contributor.
|
||||||
|
|
||||||
|
1.3. "Covered Code" means the Original Code or Modifications or the
|
||||||
|
combination of the Original Code and Modifications, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.4. "Electronic Distribution Mechanism" means a mechanism generally
|
||||||
|
accepted in the software development community for the electronic
|
||||||
|
transfer of data.
|
||||||
|
|
||||||
|
1.5. "Executable" means Covered Code in any form other than Source
|
||||||
|
Code.
|
||||||
|
|
||||||
|
1.6. "Initial Developer" means the individual or entity identified
|
||||||
|
as the Initial Developer in the Source Code notice required by Exhibit
|
||||||
|
A.
|
||||||
|
|
||||||
|
1.7. "Larger Work" means a work which combines Covered Code or
|
||||||
|
portions thereof with code not governed by the terms of this License.
|
||||||
|
|
||||||
|
1.8. "License" means this document.
|
||||||
|
|
||||||
|
1.8.1. "Licensable" means having the right to grant, to the maximum
|
||||||
|
extent possible, whether at the time of the initial grant or
|
||||||
|
subsequently acquired, any and all of the rights conveyed herein.
|
||||||
|
|
||||||
|
1.9. "Modifications" means any addition to or deletion from the
|
||||||
|
substance or structure of either the Original Code or any previous
|
||||||
|
Modifications. When Covered Code is released as a series of files, a
|
||||||
|
Modification is:
|
||||||
|
A. Any addition to or deletion from the contents of a file
|
||||||
|
containing Original Code or previous Modifications.
|
||||||
|
|
||||||
|
B. Any new file that contains any part of the Original Code or
|
||||||
|
previous Modifications.
|
||||||
|
|
||||||
|
1.10. "Original Code" means Source Code of computer software code
|
||||||
|
which is described in the Source Code notice required by Exhibit A as
|
||||||
|
Original Code, and which, at the time of its release under this
|
||||||
|
License is not already Covered Code governed by this License.
|
||||||
|
|
||||||
|
1.10.1. "Patent Claims" means any patent claim(s), now owned or
|
||||||
|
hereafter acquired, including without limitation, method, process,
|
||||||
|
and apparatus claims, in any patent Licensable by grantor.
|
||||||
|
|
||||||
|
1.11. "Source Code" means the preferred form of the Covered Code for
|
||||||
|
making modifications to it, including all modules it contains, plus
|
||||||
|
any associated interface definition files, scripts used to control
|
||||||
|
compilation and installation of an Executable, or source code
|
||||||
|
differential comparisons against either the Original Code or another
|
||||||
|
well known, available Covered Code of the Contributor's choice. The
|
||||||
|
Source Code can be in a compressed or archival form, provided the
|
||||||
|
appropriate decompression or de-archiving software is widely available
|
||||||
|
for no charge.
|
||||||
|
|
||||||
|
1.12. "You" (or "Your") means an individual or a legal entity
|
||||||
|
exercising rights under, and complying with all of the terms of, this
|
||||||
|
License or a future version of this License issued under Section 6.1.
|
||||||
|
For legal entities, "You" includes any entity which controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of
|
||||||
|
this definition, "control" means (a) the power, direct or indirect,
|
||||||
|
to cause the direction or management of such entity, whether by
|
||||||
|
contract or otherwise, or (b) ownership of more than fifty percent
|
||||||
|
(50%) of the outstanding shares or beneficial ownership of such
|
||||||
|
entity.
|
||||||
|
|
||||||
|
2. Source Code License.
|
||||||
|
|
||||||
|
2.1. The Initial Developer Grant.
|
||||||
|
The Initial Developer hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license, subject to third party intellectual property
|
||||||
|
claims:
|
||||||
|
(a) under intellectual property rights (other than patent or
|
||||||
|
trademark) Licensable by Initial Developer to use, reproduce,
|
||||||
|
modify, display, perform, sublicense and distribute the Original
|
||||||
|
Code (or portions thereof) with or without Modifications, and/or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patents Claims infringed by the making, using or
|
||||||
|
selling of Original Code, to make, have made, use, practice,
|
||||||
|
sell, and offer for sale, and/or otherwise dispose of the
|
||||||
|
Original Code (or portions thereof).
|
||||||
|
|
||||||
|
(c) the licenses granted in this Section 2.1(a) and (b) are
|
||||||
|
effective on the date Initial Developer first distributes
|
||||||
|
Original Code under the terms of this License.
|
||||||
|
|
||||||
|
(d) Notwithstanding Section 2.1(b) above, no patent license is
|
||||||
|
granted: 1) for code that You delete from the Original Code; 2)
|
||||||
|
separate from the Original Code; or 3) for infringements caused
|
||||||
|
by: i) the modification of the Original Code or ii) the
|
||||||
|
combination of the Original Code with other software or devices.
|
||||||
|
|
||||||
|
2.2. Contributor Grant.
|
||||||
|
Subject to third party intellectual property claims, each Contributor
|
||||||
|
hereby grants You a world-wide, royalty-free, non-exclusive license
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or
|
||||||
|
trademark) Licensable by Contributor, to use, reproduce, modify,
|
||||||
|
display, perform, sublicense and distribute the Modifications
|
||||||
|
created by such Contributor (or portions thereof) either on an
|
||||||
|
unmodified basis, with other Modifications, as Covered Code
|
||||||
|
and/or as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims infringed by the making, using, or
|
||||||
|
selling of Modifications made by that Contributor either alone
|
||||||
|
and/or in combination with its Contributor Version (or portions
|
||||||
|
of such combination), to make, use, sell, offer for sale, have
|
||||||
|
made, and/or otherwise dispose of: 1) Modifications made by that
|
||||||
|
Contributor (or portions thereof); and 2) the combination of
|
||||||
|
Modifications made by that Contributor with its Contributor
|
||||||
|
Version (or portions of such combination).
|
||||||
|
|
||||||
|
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
|
||||||
|
effective on the date Contributor first makes Commercial Use of
|
||||||
|
the Covered Code.
|
||||||
|
|
||||||
|
(d) Notwithstanding Section 2.2(b) above, no patent license is
|
||||||
|
granted: 1) for any code that Contributor has deleted from the
|
||||||
|
Contributor Version; 2) separate from the Contributor Version;
|
||||||
|
3) for infringements caused by: i) third party modifications of
|
||||||
|
Contributor Version or ii) the combination of Modifications made
|
||||||
|
by that Contributor with other software (except as part of the
|
||||||
|
Contributor Version) or other devices; or 4) under Patent Claims
|
||||||
|
infringed by Covered Code in the absence of Modifications made by
|
||||||
|
that Contributor.
|
||||||
|
|
||||||
|
3. Distribution Obligations.
|
||||||
|
|
||||||
|
3.1. Application of License.
|
||||||
|
The Modifications which You create or to which You contribute are
|
||||||
|
governed by the terms of this License, including without limitation
|
||||||
|
Section 2.2. The Source Code version of Covered Code may be
|
||||||
|
distributed only under the terms of this License or a future version
|
||||||
|
of this License released under Section 6.1, and You must include a
|
||||||
|
copy of this License with every copy of the Source Code You
|
||||||
|
distribute. You may not offer or impose any terms on any Source Code
|
||||||
|
version that alters or restricts the applicable version of this
|
||||||
|
License or the recipients' rights hereunder. However, You may include
|
||||||
|
an additional document offering the additional rights described in
|
||||||
|
Section 3.5.
|
||||||
|
|
||||||
|
3.2. Availability of Source Code.
|
||||||
|
Any Modification which You create or to which You contribute must be
|
||||||
|
made available in Source Code form under the terms of this License
|
||||||
|
either on the same media as an Executable version or via an accepted
|
||||||
|
Electronic Distribution Mechanism to anyone to whom you made an
|
||||||
|
Executable version available; and if made available via Electronic
|
||||||
|
Distribution Mechanism, must remain available for at least twelve (12)
|
||||||
|
months after the date it initially became available, or at least six
|
||||||
|
(6) months after a subsequent version of that particular Modification
|
||||||
|
has been made available to such recipients. You are responsible for
|
||||||
|
ensuring that the Source Code version remains available even if the
|
||||||
|
Electronic Distribution Mechanism is maintained by a third party.
|
||||||
|
|
||||||
|
3.3. Description of Modifications.
|
||||||
|
You must cause all Covered Code to which You contribute to contain a
|
||||||
|
file documenting the changes You made to create that Covered Code and
|
||||||
|
the date of any change. You must include a prominent statement that
|
||||||
|
the Modification is derived, directly or indirectly, from Original
|
||||||
|
Code provided by the Initial Developer and including the name of the
|
||||||
|
Initial Developer in (a) the Source Code, and (b) in any notice in an
|
||||||
|
Executable version or related documentation in which You describe the
|
||||||
|
origin or ownership of the Covered Code.
|
||||||
|
|
||||||
|
3.4. Intellectual Property Matters
|
||||||
|
(a) Third Party Claims.
|
||||||
|
If Contributor has knowledge that a license under a third party's
|
||||||
|
intellectual property rights is required to exercise the rights
|
||||||
|
granted by such Contributor under Sections 2.1 or 2.2,
|
||||||
|
Contributor must include a text file with the Source Code
|
||||||
|
distribution titled "LEGAL" which describes the claim and the
|
||||||
|
party making the claim in sufficient detail that a recipient will
|
||||||
|
know whom to contact. If Contributor obtains such knowledge after
|
||||||
|
the Modification is made available as described in Section 3.2,
|
||||||
|
Contributor shall promptly modify the LEGAL file in all copies
|
||||||
|
Contributor makes available thereafter and shall take other steps
|
||||||
|
(such as notifying appropriate mailing lists or newsgroups)
|
||||||
|
reasonably calculated to inform those who received the Covered
|
||||||
|
Code that new knowledge has been obtained.
|
||||||
|
|
||||||
|
(b) Contributor APIs.
|
||||||
|
If Contributor's Modifications include an application programming
|
||||||
|
interface and Contributor has knowledge of patent licenses which
|
||||||
|
are reasonably necessary to implement that API, Contributor must
|
||||||
|
also include this information in the LEGAL file.
|
||||||
|
|
||||||
|
(c) Representations.
|
||||||
|
Contributor represents that, except as disclosed pursuant to
|
||||||
|
Section 3.4(a) above, Contributor believes that Contributor's
|
||||||
|
Modifications are Contributor's original creation(s) and/or
|
||||||
|
Contributor has sufficient rights to grant the rights conveyed by
|
||||||
|
this License.
|
||||||
|
|
||||||
|
3.5. Required Notices.
|
||||||
|
You must duplicate the notice in Exhibit A in each file of the Source
|
||||||
|
Code. If it is not possible to put such notice in a particular Source
|
||||||
|
Code file due to its structure, then You must include such notice in a
|
||||||
|
location (such as a relevant directory) where a user would be likely
|
||||||
|
to look for such a notice. If You created one or more Modification(s)
|
||||||
|
You may add your name as a Contributor to the notice described in
|
||||||
|
Exhibit A. You must also duplicate this License in any documentation
|
||||||
|
for the Source Code where You describe recipients' rights or ownership
|
||||||
|
rights relating to Covered Code. You may choose to offer, and to
|
||||||
|
charge a fee for, warranty, support, indemnity or liability
|
||||||
|
obligations to one or more recipients of Covered Code. However, You
|
||||||
|
may do so only on Your own behalf, and not on behalf of the Initial
|
||||||
|
Developer or any Contributor. You must make it absolutely clear than
|
||||||
|
any such warranty, support, indemnity or liability obligation is
|
||||||
|
offered by You alone, and You hereby agree to indemnify the Initial
|
||||||
|
Developer and every Contributor for any liability incurred by the
|
||||||
|
Initial Developer or such Contributor as a result of warranty,
|
||||||
|
support, indemnity or liability terms You offer.
|
||||||
|
|
||||||
|
3.6. Distribution of Executable Versions.
|
||||||
|
You may distribute Covered Code in Executable form only if the
|
||||||
|
requirements of Section 3.1-3.5 have been met for that Covered Code,
|
||||||
|
and if You include a notice stating that the Source Code version of
|
||||||
|
the Covered Code is available under the terms of this License,
|
||||||
|
including a description of how and where You have fulfilled the
|
||||||
|
obligations of Section 3.2. The notice must be conspicuously included
|
||||||
|
in any notice in an Executable version, related documentation or
|
||||||
|
collateral in which You describe recipients' rights relating to the
|
||||||
|
Covered Code. You may distribute the Executable version of Covered
|
||||||
|
Code or ownership rights under a license of Your choice, which may
|
||||||
|
contain terms different from this License, provided that You are in
|
||||||
|
compliance with the terms of this License and that the license for the
|
||||||
|
Executable version does not attempt to limit or alter the recipient's
|
||||||
|
rights in the Source Code version from the rights set forth in this
|
||||||
|
License. If You distribute the Executable version under a different
|
||||||
|
license You must make it absolutely clear that any terms which differ
|
||||||
|
from this License are offered by You alone, not by the Initial
|
||||||
|
Developer or any Contributor. You hereby agree to indemnify the
|
||||||
|
Initial Developer and every Contributor for any liability incurred by
|
||||||
|
the Initial Developer or such Contributor as a result of any such
|
||||||
|
terms You offer.
|
||||||
|
|
||||||
|
3.7. Larger Works.
|
||||||
|
You may create a Larger Work by combining Covered Code with other code
|
||||||
|
not governed by the terms of this License and distribute the Larger
|
||||||
|
Work as a single product. In such a case, You must make sure the
|
||||||
|
requirements of this License are fulfilled for the Covered Code.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation.
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Code due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description
|
||||||
|
must be included in the LEGAL file described in Section 3.4 and must
|
||||||
|
be included with all distributions of the Source Code. Except to the
|
||||||
|
extent prohibited by statute or regulation, such description must be
|
||||||
|
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||||
|
understand it.
|
||||||
|
|
||||||
|
5. Application of this License.
|
||||||
|
|
||||||
|
This License applies to code to which the Initial Developer has
|
||||||
|
attached the notice in Exhibit A and to related Covered Code.
|
||||||
|
|
||||||
|
6. Versions of the License.
|
||||||
|
|
||||||
|
6.1. New Versions.
|
||||||
|
Netscape Communications Corporation ("Netscape") may publish revised
|
||||||
|
and/or new versions of the License from time to time. Each version
|
||||||
|
will be given a distinguishing version number.
|
||||||
|
|
||||||
|
6.2. Effect of New Versions.
|
||||||
|
Once Covered Code has been published under a particular version of the
|
||||||
|
License, You may always continue to use it under the terms of that
|
||||||
|
version. You may also choose to use such Covered Code under the terms
|
||||||
|
of any subsequent version of the License published by Netscape. No one
|
||||||
|
other than Netscape has the right to modify the terms applicable to
|
||||||
|
Covered Code created under this License.
|
||||||
|
|
||||||
|
6.3. Derivative Works.
|
||||||
|
If You create or use a modified version of this License (which you may
|
||||||
|
only do in order to apply it to code which is not already Covered Code
|
||||||
|
governed by this License), You must (a) rename Your license so that
|
||||||
|
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
|
||||||
|
"MPL", "NPL" or any confusingly similar phrase do not appear in your
|
||||||
|
license (except to note that your license differs from this License)
|
||||||
|
and (b) otherwise make it clear that Your version of the license
|
||||||
|
contains terms which differ from the Mozilla Public License and
|
||||||
|
Netscape Public License. (Filling in the name of the Initial
|
||||||
|
Developer, Original Code or Contributor in the notice described in
|
||||||
|
Exhibit A shall not of themselves be deemed to be modifications of
|
||||||
|
this License.)
|
||||||
|
|
||||||
|
7. DISCLAIMER OF WARRANTY.
|
||||||
|
|
||||||
|
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
||||||
|
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
|
||||||
|
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
|
||||||
|
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
|
||||||
|
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
|
||||||
|
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
|
||||||
|
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
|
||||||
|
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
|
||||||
|
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
|
||||||
|
|
||||||
|
8. TERMINATION.
|
||||||
|
|
||||||
|
8.1. This License and the rights granted hereunder will terminate
|
||||||
|
automatically if You fail to comply with terms herein and fail to cure
|
||||||
|
such breach within 30 days of becoming aware of the breach. All
|
||||||
|
sublicenses to the Covered Code which are properly granted shall
|
||||||
|
survive any termination of this License. Provisions which, by their
|
||||||
|
nature, must remain in effect beyond the termination of this License
|
||||||
|
shall survive.
|
||||||
|
|
||||||
|
8.2. If You initiate litigation by asserting a patent infringement
|
||||||
|
claim (excluding declatory judgment actions) against Initial Developer
|
||||||
|
or a Contributor (the Initial Developer or Contributor against whom
|
||||||
|
You file such action is referred to as "Participant") alleging that:
|
||||||
|
|
||||||
|
(a) such Participant's Contributor Version directly or indirectly
|
||||||
|
infringes any patent, then any and all rights granted by such
|
||||||
|
Participant to You under Sections 2.1 and/or 2.2 of this License
|
||||||
|
shall, upon 60 days notice from Participant terminate prospectively,
|
||||||
|
unless if within 60 days after receipt of notice You either: (i)
|
||||||
|
agree in writing to pay Participant a mutually agreeable reasonable
|
||||||
|
royalty for Your past and future use of Modifications made by such
|
||||||
|
Participant, or (ii) withdraw Your litigation claim with respect to
|
||||||
|
the Contributor Version against such Participant. If within 60 days
|
||||||
|
of notice, a reasonable royalty and payment arrangement are not
|
||||||
|
mutually agreed upon in writing by the parties or the litigation claim
|
||||||
|
is not withdrawn, the rights granted by Participant to You under
|
||||||
|
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
|
||||||
|
the 60 day notice period specified above.
|
||||||
|
|
||||||
|
(b) any software, hardware, or device, other than such Participant's
|
||||||
|
Contributor Version, directly or indirectly infringes any patent, then
|
||||||
|
any rights granted to You by such Participant under Sections 2.1(b)
|
||||||
|
and 2.2(b) are revoked effective as of the date You first made, used,
|
||||||
|
sold, distributed, or had made, Modifications made by that
|
||||||
|
Participant.
|
||||||
|
|
||||||
|
8.3. If You assert a patent infringement claim against Participant
|
||||||
|
alleging that such Participant's Contributor Version directly or
|
||||||
|
indirectly infringes any patent where such claim is resolved (such as
|
||||||
|
by license or settlement) prior to the initiation of patent
|
||||||
|
infringement litigation, then the reasonable value of the licenses
|
||||||
|
granted by such Participant under Sections 2.1 or 2.2 shall be taken
|
||||||
|
into account in determining the amount or value of any payment or
|
||||||
|
license.
|
||||||
|
|
||||||
|
8.4. In the event of termination under Sections 8.1 or 8.2 above,
|
||||||
|
all end user license agreements (excluding distributors and resellers)
|
||||||
|
which have been validly granted by You or any distributor hereunder
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
9. LIMITATION OF LIABILITY.
|
||||||
|
|
||||||
|
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
|
||||||
|
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
|
||||||
|
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
|
||||||
|
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
|
||||||
|
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
|
||||||
|
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
|
||||||
|
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
|
||||||
|
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
|
||||||
|
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
|
||||||
|
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
|
||||||
|
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
|
||||||
|
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
|
||||||
|
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
|
||||||
|
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
10. U.S. GOVERNMENT END USERS.
|
||||||
|
|
||||||
|
The Covered Code is a "commercial item," as that term is defined in
|
||||||
|
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
|
||||||
|
software" and "commercial computer software documentation," as such
|
||||||
|
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
|
||||||
|
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
|
||||||
|
all U.S. Government End Users acquire Covered Code with only those
|
||||||
|
rights set forth herein.
|
||||||
|
|
||||||
|
11. MISCELLANEOUS.
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. This License shall be governed by
|
||||||
|
California law provisions (except to the extent applicable law, if
|
||||||
|
any, provides otherwise), excluding its conflict-of-law provisions.
|
||||||
|
With respect to disputes in which at least one party is a citizen of,
|
||||||
|
or an entity chartered or registered to do business in the United
|
||||||
|
States of America, any litigation relating to this License shall be
|
||||||
|
subject to the jurisdiction of the Federal Courts of the Northern
|
||||||
|
District of California, with venue lying in Santa Clara County,
|
||||||
|
California, with the losing party responsible for costs, including
|
||||||
|
without limitation, court costs and reasonable attorneys' fees and
|
||||||
|
expenses. The application of the United Nations Convention on
|
||||||
|
Contracts for the International Sale of Goods is expressly excluded.
|
||||||
|
Any law or regulation which provides that the language of a contract
|
||||||
|
shall be construed against the drafter shall not apply to this
|
||||||
|
License.
|
||||||
|
|
||||||
|
12. RESPONSIBILITY FOR CLAIMS.
|
||||||
|
|
||||||
|
As between Initial Developer and the Contributors, each party is
|
||||||
|
responsible for claims and damages arising, directly or indirectly,
|
||||||
|
out of its utilization of rights under this License and You agree to
|
||||||
|
work with Initial Developer and Contributors to distribute such
|
||||||
|
responsibility on an equitable basis. Nothing herein is intended or
|
||||||
|
shall be deemed to constitute any admission of liability.
|
||||||
|
|
||||||
|
13. MULTIPLE-LICENSED CODE.
|
||||||
|
|
||||||
|
Initial Developer may designate portions of the Covered Code as
|
||||||
|
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
|
||||||
|
Developer permits you to utilize portions of the Covered Code under
|
||||||
|
Your choice of the NPL or the alternative licenses, if any, specified
|
||||||
|
by the Initial Developer in the file described in Exhibit A.
|
||||||
|
|
||||||
|
EXHIBIT A -Mozilla Public License.
|
||||||
|
|
||||||
|
``The contents of this file are subject to the Mozilla Public License
|
||||||
|
Version 1.1 (the "License"); you may not use this file except in
|
||||||
|
compliance with the License. You may obtain a copy of the License at
|
||||||
|
http://www.mozilla.org/MPL/
|
||||||
|
|
||||||
|
Software distributed under the License is distributed on an "AS IS"
|
||||||
|
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing rights and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
The Original Code is ______________________________________.
|
||||||
|
|
||||||
|
The Initial Developer of the Original Code is ________________________.
|
||||||
|
Portions created by ______________________ are Copyright (C) ______
|
||||||
|
_______________________. All Rights Reserved.
|
||||||
|
|
||||||
|
Contributor(s): ______________________________________.
|
||||||
|
|
||||||
|
Alternatively, the contents of this file may be used under the terms
|
||||||
|
of the _____ license (the "[___] License"), in which case the
|
||||||
|
provisions of [______] License are applicable instead of those
|
||||||
|
above. If you wish to allow use of your version of this file only
|
||||||
|
under the terms of the [____] License and not to allow others to use
|
||||||
|
your version of this file under the MPL, indicate your decision by
|
||||||
|
deleting the provisions above and replace them with the notice and
|
||||||
|
other provisions required by the [___] License. If you do not delete
|
||||||
|
the provisions above, a recipient may use your version of this file
|
||||||
|
under either the MPL or the [___] License."
|
||||||
|
|
||||||
|
[NOTE: The text of this Exhibit A may differ slightly from the text of
|
||||||
|
the notices in the Source Code files of the Original Code. You should
|
||||||
|
use the text of this Exhibit A rather than the text found in the
|
||||||
|
Original Code Source Code for Your Modifications.]
|
||||||
|
|
167
Frameworks/TagLib/taglib/INSTALL
Normal file
167
Frameworks/TagLib/taglib/INSTALL
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
Basic Installation
|
||||||
|
==================
|
||||||
|
|
||||||
|
These are generic installation instructions.
|
||||||
|
|
||||||
|
The `configure' shell script attempts to guess correct values for
|
||||||
|
various system-dependent variables used during compilation. It uses
|
||||||
|
those values to create a `Makefile' in each directory of the package.
|
||||||
|
It may also create one or more `.h' files containing system-dependent
|
||||||
|
definitions. Finally, it creates a shell script `config.status' that
|
||||||
|
you can run in the future to recreate the current configuration, a file
|
||||||
|
`config.cache' that saves the results of its tests to speed up
|
||||||
|
reconfiguring, and a file `config.log' containing compiler output
|
||||||
|
(useful mainly for debugging `configure').
|
||||||
|
|
||||||
|
If you need to do unusual things to compile the package, please try
|
||||||
|
to figure out how `configure' could check whether to do them, and mail
|
||||||
|
diffs or instructions to the address given in the `README' so they can
|
||||||
|
be considered for the next release. If at some point `config.cache'
|
||||||
|
contains results you don't want to keep, you may remove or edit it.
|
||||||
|
|
||||||
|
The file `configure.in' is used to create `configure' by a program
|
||||||
|
called `autoconf'. You only need `configure.in' if you want to change
|
||||||
|
it or regenerate `configure' using a newer version of `autoconf'.
|
||||||
|
|
||||||
|
The simplest way to compile this package is:
|
||||||
|
|
||||||
|
1. `cd' to the directory containing the package's source code and type
|
||||||
|
`./configure' to configure the package for your system. If you're
|
||||||
|
using `csh' on an old version of System V, you might need to type
|
||||||
|
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||||
|
`configure' itself.
|
||||||
|
|
||||||
|
Running `configure' takes a while. While running, it prints some
|
||||||
|
messages telling which features it is checking for.
|
||||||
|
|
||||||
|
2. Type `make' to compile the package.
|
||||||
|
|
||||||
|
3. Type `make install' to install the programs and any data files and
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
4. You can remove the program binaries and object files from the
|
||||||
|
source code directory by typing `make clean'.
|
||||||
|
|
||||||
|
Compilers and Options
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Some systems require unusual options for compilation or linking that
|
||||||
|
the `configure' script does not know about. You can give `configure'
|
||||||
|
initial values for variables by setting them in the environment. Using
|
||||||
|
a Bourne-compatible shell, you can do that on the command line like
|
||||||
|
this:
|
||||||
|
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
|
||||||
|
|
||||||
|
Or on systems that have the `env' program, you can do it like this:
|
||||||
|
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
|
||||||
|
|
||||||
|
Compiling For Multiple Architectures
|
||||||
|
====================================
|
||||||
|
|
||||||
|
You can compile the package for more than one kind of computer at the
|
||||||
|
same time, by placing the object files for each architecture in their
|
||||||
|
own directory. To do this, you must use a version of `make' that
|
||||||
|
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||||
|
directory where you want the object files and executables to go and run
|
||||||
|
the `configure' script. `configure' automatically checks for the
|
||||||
|
source code in the directory that `configure' is in and in `..'.
|
||||||
|
|
||||||
|
If you have to use a `make' that does not supports the `VPATH'
|
||||||
|
variable, you have to compile the package for one architecture at a time
|
||||||
|
in the source code directory. After you have installed the package for
|
||||||
|
one architecture, use `make distclean' before reconfiguring for another
|
||||||
|
architecture.
|
||||||
|
|
||||||
|
Installation Names
|
||||||
|
==================
|
||||||
|
|
||||||
|
By default, `make install' will install the package's files in
|
||||||
|
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||||
|
installation prefix other than `/usr/local' by giving `configure' the
|
||||||
|
option `--prefix=PATH'.
|
||||||
|
|
||||||
|
You can specify separate installation prefixes for
|
||||||
|
architecture-specific files and architecture-independent files. If you
|
||||||
|
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||||
|
PATH as the prefix for installing programs and libraries.
|
||||||
|
Documentation and other data files will still use the regular prefix.
|
||||||
|
|
||||||
|
If the package supports it, you can cause programs to be installed
|
||||||
|
with an extra prefix or suffix on their names by giving `configure' the
|
||||||
|
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||||
|
|
||||||
|
Optional Features
|
||||||
|
=================
|
||||||
|
|
||||||
|
Some packages pay attention to `--enable-FEATURE' options to
|
||||||
|
`configure', where FEATURE indicates an optional part of the package.
|
||||||
|
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||||
|
is something like `gnu-as' or `x' (for the X Window System). The
|
||||||
|
`README' should mention any `--enable-' and `--with-' options that the
|
||||||
|
package recognizes.
|
||||||
|
|
||||||
|
For packages that use the X Window System, `configure' can usually
|
||||||
|
find the X include and library files automatically, but if it doesn't,
|
||||||
|
you can use the `configure' options `--x-includes=DIR' and
|
||||||
|
`--x-libraries=DIR' to specify their locations.
|
||||||
|
|
||||||
|
Specifying the System Type
|
||||||
|
==========================
|
||||||
|
|
||||||
|
There may be some features `configure' can not figure out
|
||||||
|
automatically, but needs to determine by the type of host the package
|
||||||
|
will run on. Usually `configure' can figure that out, but if it prints
|
||||||
|
a message saying it can not guess the host type, give it the
|
||||||
|
`--host=TYPE' option. TYPE can either be a short name for the system
|
||||||
|
type, such as `sun4', or a canonical name with three fields:
|
||||||
|
CPU-COMPANY-SYSTEM
|
||||||
|
|
||||||
|
See the file `config.sub' for the possible values of each field. If
|
||||||
|
`config.sub' isn't included in this package, then this package doesn't
|
||||||
|
need to know the host type.
|
||||||
|
|
||||||
|
If you are building compiler tools for cross-compiling, you can also
|
||||||
|
use the `--target=TYPE' option to select the type of system they will
|
||||||
|
produce code for and the `--build=TYPE' option to select the type of
|
||||||
|
system on which you are compiling the package.
|
||||||
|
|
||||||
|
Sharing Defaults
|
||||||
|
================
|
||||||
|
|
||||||
|
If you want to set default values for `configure' scripts to share,
|
||||||
|
you can create a site shell script called `config.site' that gives
|
||||||
|
default values for variables like `CC', `cache_file', and `prefix'.
|
||||||
|
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||||
|
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||||
|
`CONFIG_SITE' environment variable to the location of the site script.
|
||||||
|
A warning: not all `configure' scripts look for a site script.
|
||||||
|
|
||||||
|
Operation Controls
|
||||||
|
==================
|
||||||
|
|
||||||
|
`configure' recognizes the following options to control how it
|
||||||
|
operates.
|
||||||
|
|
||||||
|
`--cache-file=FILE'
|
||||||
|
Use and save the results of the tests in FILE instead of
|
||||||
|
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
|
||||||
|
debugging `configure'.
|
||||||
|
|
||||||
|
`--help'
|
||||||
|
Print a summary of the options to `configure', and exit.
|
||||||
|
|
||||||
|
`--quiet'
|
||||||
|
`--silent'
|
||||||
|
`-q'
|
||||||
|
Do not print messages saying which checks are being made.
|
||||||
|
|
||||||
|
`--srcdir=DIR'
|
||||||
|
Look for the package's source code in directory DIR. Usually
|
||||||
|
`configure' can determine that directory automatically.
|
||||||
|
|
||||||
|
`--version'
|
||||||
|
Print the version of Autoconf used to generate the `configure'
|
||||||
|
script, and exit.
|
||||||
|
|
||||||
|
`configure' also accepts some other, not widely useful, options.
|
||||||
|
|
65
Frameworks/TagLib/taglib/config.h
Normal file
65
Frameworks/TagLib/taglib/config.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/* config.h. Generated from config.h.in by configure. */
|
||||||
|
/* config.h.in. Generated from configure.in by autoheader. */
|
||||||
|
|
||||||
|
/* have cppunit */
|
||||||
|
#define HAVE_CPPUNIT 0
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
|
#define HAVE_DLFCN_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#define HAVE_INTTYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#define HAVE_MEMORY_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||||
|
#define HAVE_STDLIB_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#define HAVE_STRINGS_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <string.h> header file. */
|
||||||
|
#define HAVE_STRING_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
|
#define HAVE_SYS_STAT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
|
#define HAVE_SYS_TYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
|
#define HAVE_UNISTD_H 1
|
||||||
|
|
||||||
|
/* have zlib */
|
||||||
|
#define HAVE_ZLIB 1
|
||||||
|
|
||||||
|
/* Suffix for lib directories */
|
||||||
|
#define KDELIBSUFF ""
|
||||||
|
|
||||||
|
/* Name of package */
|
||||||
|
#define PACKAGE "taglib"
|
||||||
|
|
||||||
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
|
#define PACKAGE_BUGREPORT ""
|
||||||
|
|
||||||
|
/* Define to the full name of this package. */
|
||||||
|
#define PACKAGE_NAME ""
|
||||||
|
|
||||||
|
/* Define to the full name and version of this package. */
|
||||||
|
#define PACKAGE_STRING ""
|
||||||
|
|
||||||
|
/* Define to the one symbol short name of this package. */
|
||||||
|
#define PACKAGE_TARNAME ""
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#define PACKAGE_VERSION ""
|
||||||
|
|
||||||
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
|
#define STDC_HEADERS 1
|
||||||
|
|
||||||
|
/* Version number of package */
|
||||||
|
#define VERSION "1.5"
|
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
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
|
||||||
|
#include "apefooter.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace APE;
|
||||||
|
|
||||||
|
class Footer::FooterPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FooterPrivate() : version(0),
|
||||||
|
footerPresent(true),
|
||||||
|
headerPresent(false),
|
||||||
|
isHeader(false),
|
||||||
|
itemCount(0),
|
||||||
|
tagSize(0) {}
|
||||||
|
|
||||||
|
~FooterPrivate() {}
|
||||||
|
|
||||||
|
uint version;
|
||||||
|
|
||||||
|
bool footerPresent;
|
||||||
|
bool headerPresent;
|
||||||
|
|
||||||
|
bool isHeader;
|
||||||
|
|
||||||
|
uint itemCount;
|
||||||
|
uint tagSize;
|
||||||
|
|
||||||
|
static const uint size = 32;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
TagLib::uint Footer::size()
|
||||||
|
{
|
||||||
|
return FooterPrivate::size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Footer::fileIdentifier()
|
||||||
|
{
|
||||||
|
return ByteVector::fromCString("APETAGEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Footer::Footer()
|
||||||
|
{
|
||||||
|
d = new FooterPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Footer::Footer(const ByteVector &data)
|
||||||
|
{
|
||||||
|
d = new FooterPrivate;
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Footer::~Footer()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Footer::version() const
|
||||||
|
{
|
||||||
|
return d->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Footer::headerPresent() const
|
||||||
|
{
|
||||||
|
return d->headerPresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Footer::footerPresent() const
|
||||||
|
{
|
||||||
|
return d->footerPresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Footer::isHeader() const
|
||||||
|
{
|
||||||
|
return d->isHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Footer::setHeaderPresent(bool b) const
|
||||||
|
{
|
||||||
|
d->headerPresent = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Footer::itemCount() const
|
||||||
|
{
|
||||||
|
return d->itemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Footer::setItemCount(uint s)
|
||||||
|
{
|
||||||
|
d->itemCount = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Footer::tagSize() const
|
||||||
|
{
|
||||||
|
return d->tagSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Footer::completeTagSize() const
|
||||||
|
{
|
||||||
|
if(d->headerPresent)
|
||||||
|
return d->tagSize + d->size;
|
||||||
|
else
|
||||||
|
return d->tagSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Footer::setTagSize(uint s)
|
||||||
|
{
|
||||||
|
d->tagSize = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Footer::setData(const ByteVector &data)
|
||||||
|
{
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Footer::renderFooter() const
|
||||||
|
{
|
||||||
|
return render(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Footer::renderHeader() const
|
||||||
|
{
|
||||||
|
if (!d->headerPresent) return ByteVector();
|
||||||
|
|
||||||
|
return render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Footer::parse(const ByteVector &data)
|
||||||
|
{
|
||||||
|
if(data.size() < size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".
|
||||||
|
|
||||||
|
// Read the version number
|
||||||
|
|
||||||
|
d->version = data.mid(8, 4).toUInt(false);
|
||||||
|
|
||||||
|
// Read the tag size
|
||||||
|
|
||||||
|
d->tagSize = data.mid(12, 4).toUInt(false);
|
||||||
|
|
||||||
|
// Read the item count
|
||||||
|
|
||||||
|
d->itemCount = data.mid(16, 4).toUInt(false);
|
||||||
|
|
||||||
|
// Read the flags
|
||||||
|
|
||||||
|
std::bitset<32> flags(data.mid(20, 4).toUInt(false));
|
||||||
|
|
||||||
|
d->headerPresent = flags[31];
|
||||||
|
d->footerPresent = !flags[30];
|
||||||
|
d->isHeader = flags[29];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Footer::render(bool isHeader) const
|
||||||
|
{
|
||||||
|
ByteVector v;
|
||||||
|
|
||||||
|
// add the file identifier -- "APETAGEX"
|
||||||
|
|
||||||
|
v.append(fileIdentifier());
|
||||||
|
|
||||||
|
// add the version number -- we always render a 2.000 tag regardless of what
|
||||||
|
// the tag originally was.
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(2000, false));
|
||||||
|
|
||||||
|
// add the tag size
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(d->tagSize, false));
|
||||||
|
|
||||||
|
// add the item count
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(d->itemCount, false));
|
||||||
|
|
||||||
|
// render and add the flags
|
||||||
|
|
||||||
|
std::bitset<32> flags;
|
||||||
|
|
||||||
|
flags[31] = d->headerPresent;
|
||||||
|
flags[30] = false; // footer is always present
|
||||||
|
flags[29] = isHeader;
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(flags.to_ulong(), false));
|
||||||
|
|
||||||
|
// add the reserved 64bit
|
||||||
|
|
||||||
|
v.append(ByteVector::fromLongLong(0));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
229
Frameworks/TagLib/taglib/taglib/ape/apeitem.cpp
Normal file
229
Frameworks/TagLib/taglib/taglib/ape/apeitem.cpp
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This library is distributed in the hope that it will be useful, but *
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||||
|
* Lesser General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 0:
|
||||||
|
case 1:
|
||||||
|
if(d->text.isEmpty())
|
||||||
|
return true;
|
||||||
|
if(d->text.size() == 1 && d->text.front().isEmpty())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
case 2:
|
||||||
|
return d->value.isEmpty();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::parse(const ByteVector &data)
|
||||||
|
{
|
||||||
|
// 11 bytes is the minimum size for an APE item
|
||||||
|
|
||||||
|
if(data.size() < 11) {
|
||||||
|
debug("APE::Item::parse() -- no data in item");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint valueLength = data.mid(0, 4).toUInt(false);
|
||||||
|
uint flags = data.mid(4, 4).toUInt(false);
|
||||||
|
|
||||||
|
d->key = String(data.mid(8), String::UTF8);
|
||||||
|
|
||||||
|
d->value = data.mid(8 + d->key.size() + 1, valueLength);
|
||||||
|
|
||||||
|
setReadOnly(flags & 1);
|
||||||
|
setType(ItemTypes((flags >> 1) & 3));
|
||||||
|
|
||||||
|
if(int(d->type) < 2)
|
||||||
|
d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Item::render() const
|
||||||
|
{
|
||||||
|
ByteVector data;
|
||||||
|
TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
|
||||||
|
ByteVector value;
|
||||||
|
|
||||||
|
if(isEmpty())
|
||||||
|
return data;
|
||||||
|
|
||||||
|
if(d->type != Item::Binary) {
|
||||||
|
StringList::ConstIterator it = d->text.begin();
|
||||||
|
value.append(it->data(String::UTF8));
|
||||||
|
it++;
|
||||||
|
for(; it != d->text.end(); ++it) {
|
||||||
|
value.append('\0');
|
||||||
|
value.append(it->data(String::UTF8));
|
||||||
|
}
|
||||||
|
d->value = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value.append(d->value);
|
||||||
|
|
||||||
|
data.append(ByteVector::fromUInt(value.size(), false));
|
||||||
|
data.append(ByteVector::fromUInt(flags, false));
|
||||||
|
data.append(d->key.data(String::UTF8));
|
||||||
|
data.append(ByteVector('\0'));
|
||||||
|
data.append(value);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
||||||
|
|
||||||
|
|
266
Frameworks/TagLib/taglib/taglib/ape/apetag.cpp
Normal file
266
Frameworks/TagLib/taglib/taglib/ape/apetag.cpp
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This library is distributed in the hope that it will be useful, but *
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||||
|
* Lesser General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setTitle(const String &s)
|
||||||
|
{
|
||||||
|
addValue("TITLE", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setArtist(const String &s)
|
||||||
|
{
|
||||||
|
addValue("ARTIST", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setAlbum(const String &s)
|
||||||
|
{
|
||||||
|
addValue("ALBUM", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setComment(const String &s)
|
||||||
|
{
|
||||||
|
addValue("COMMENT", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setGenre(const String &s)
|
||||||
|
{
|
||||||
|
addValue("GENRE", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setYear(uint i)
|
||||||
|
{
|
||||||
|
if(i <= 0)
|
||||||
|
removeItem("YEAR");
|
||||||
|
else
|
||||||
|
addValue("YEAR", String::number(i), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setTrack(uint i)
|
||||||
|
{
|
||||||
|
if(i <= 0)
|
||||||
|
removeItem("TRACK");
|
||||||
|
else
|
||||||
|
addValue("TRACK", String::number(i), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Footer *APE::Tag::footer() const
|
||||||
|
{
|
||||||
|
return &d->footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const APE::ItemListMap& APE::Tag::itemListMap() const
|
||||||
|
{
|
||||||
|
return d->itemListMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::removeItem(const String &key)
|
||||||
|
{
|
||||||
|
Map<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);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
162
Frameworks/TagLib/taglib/taglib/ape/apetag.h
Normal file
162
Frameworks/TagLib/taglib/taglib/ape/apetag.h
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This library is distributed in the hope that it will be useful, but *
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||||
|
* Lesser General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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(File *file, long footerLocation);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this Tag instance.
|
||||||
|
*/
|
||||||
|
virtual ~Tag();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Renders the in memory values to a ByteVector suitable for writing to
|
||||||
|
* the file.
|
||||||
|
*/
|
||||||
|
ByteVector render() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the string "APETAGEX" suitable for usage in locating the tag in a
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
static ByteVector fileIdentifier();
|
||||||
|
|
||||||
|
// Reimplementations.
|
||||||
|
|
||||||
|
virtual String title() const;
|
||||||
|
virtual String artist() const;
|
||||||
|
virtual String album() const;
|
||||||
|
virtual String comment() const;
|
||||||
|
virtual String genre() const;
|
||||||
|
virtual uint year() const;
|
||||||
|
virtual uint track() const;
|
||||||
|
|
||||||
|
virtual void setTitle(const String &s);
|
||||||
|
virtual void setArtist(const String &s);
|
||||||
|
virtual void setAlbum(const String &s);
|
||||||
|
virtual void setComment(const String &s);
|
||||||
|
virtual void setGenre(const String &s);
|
||||||
|
virtual void setYear(uint i);
|
||||||
|
virtual void setTrack(uint i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the tag's footer.
|
||||||
|
*/
|
||||||
|
Footer *footer() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a reference to the item list map. This is an ItemListMap of
|
||||||
|
* all of the items in the tag.
|
||||||
|
*
|
||||||
|
* This is the most powerfull structure for accessing the items of the tag.
|
||||||
|
*
|
||||||
|
* \warning You should not modify this data structure directly, instead
|
||||||
|
* use setItem() and removeItem().
|
||||||
|
*/
|
||||||
|
const ItemListMap &itemListMap() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes the \a key item from the tag
|
||||||
|
*/
|
||||||
|
void removeItem(const String &key);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Adds to the item specified by \a key the data \a value. If \a replace
|
||||||
|
* is true, then all of the other values on the same key will be removed
|
||||||
|
* first.
|
||||||
|
*/
|
||||||
|
void addValue(const String &key, const String &value, bool replace = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the \a key item to the value of \a item. If an item with the \a key is already
|
||||||
|
* present, it will be replaced.
|
||||||
|
*/
|
||||||
|
void setItem(const String &key, const Item &item);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Reads from the file specified in the constructor.
|
||||||
|
*/
|
||||||
|
void read();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Parses the body of the tag in \a data.
|
||||||
|
*/
|
||||||
|
void parse(const ByteVector &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tag(const Tag &);
|
||||||
|
Tag &operator=(const Tag &);
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
203
Frameworks/TagLib/taglib/taglib/fileref.cpp
Normal file
203
Frameworks/TagLib/taglib/taglib/fileref.cpp
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tfile.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
|
||||||
|
#include "fileref.h"
|
||||||
|
#include "mpegfile.h"
|
||||||
|
#include "vorbisfile.h"
|
||||||
|
#include "flacfile.h"
|
||||||
|
#include "oggflacfile.h"
|
||||||
|
#include "mpcfile.h"
|
||||||
|
#include "wavpackfile.h"
|
||||||
|
#include "speexfile.h"
|
||||||
|
#include "trueaudiofile.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
|
||||||
|
{
|
||||||
|
return d->file->tag();
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioProperties *FileRef::audioProperties() const
|
||||||
|
{
|
||||||
|
return d->file->audioProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
File *FileRef::file() const
|
||||||
|
{
|
||||||
|
return d->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRef::save()
|
||||||
|
{
|
||||||
|
return d->file->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
if(s.size() > 4) {
|
||||||
|
if(s.substr(s.size() - 4, 4).upper() == ".OGG")
|
||||||
|
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(s.substr(s.size() - 4, 4).upper() == ".MP3")
|
||||||
|
return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(s.substr(s.size() - 4, 4).upper() == ".OGA")
|
||||||
|
return new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(s.substr(s.size() - 5, 5).upper() == ".FLAC")
|
||||||
|
return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(s.substr(s.size() - 4, 4).upper() == ".MPC")
|
||||||
|
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(s.substr(s.size() - 3, 3).upper() == ".WV")
|
||||||
|
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(s.substr(s.size() - 4, 4).upper() == ".SPX")
|
||||||
|
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(s.substr(s.size() - 4, 4).upper() == ".TTA")
|
||||||
|
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
262
Frameworks/TagLib/taglib/taglib/fileref.h
Normal file
262
Frameworks/TagLib/taglib/taglib/fileref.h
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// do not fix compiler warning about missing virtual destructor
|
||||||
|
// since this would not be binary compatible
|
||||||
|
// let Scott fix it whenever he thinks BIC changes can next be applied
|
||||||
|
/*!
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* \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
|
431
Frameworks/TagLib/taglib/taglib/flac/flacfile.cpp
Normal file
431
Frameworks/TagLib/taglib/taglib/flac/flacfile.cpp
Normal file
|
@ -0,0 +1,431 @@
|
||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003-2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This library is distributed in the hope that it will be useful, but *
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||||
|
* Lesser General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 "flacfile.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum { XiphIndex = 0, ID3v2Index = 1, ID3v1Index = 2 };
|
||||||
|
enum { StreamInfo = 0, Padding, Application, SeekTable, VorbisComment, CueSheet };
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
delete properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ID3v2::FrameFactory *ID3v2FrameFactory;
|
||||||
|
long ID3v2Location;
|
||||||
|
uint ID3v2OriginalSize;
|
||||||
|
|
||||||
|
long ID3v1Location;
|
||||||
|
|
||||||
|
TagUnion tag;
|
||||||
|
|
||||||
|
Properties *properties;
|
||||||
|
ByteVector streamInfoData;
|
||||||
|
ByteVector xiphCommentData;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new vorbis comments
|
||||||
|
|
||||||
|
Tag::duplicate(&d->tag, xiphComment(true), true);
|
||||||
|
|
||||||
|
d->xiphCommentData = xiphComment()->render(false);
|
||||||
|
|
||||||
|
// A Xiph comment portion of the data stream starts with a 4-byte descriptor.
|
||||||
|
// The first byte indicates the frame type. The last three bytes are used
|
||||||
|
// to give the length of the data segment. Here we start
|
||||||
|
|
||||||
|
ByteVector data = ByteVector::fromUInt(d->xiphCommentData.size());
|
||||||
|
|
||||||
|
data[0] = char(VorbisComment);
|
||||||
|
data.append(d->xiphCommentData);
|
||||||
|
|
||||||
|
|
||||||
|
// If file already have comment => find and update it
|
||||||
|
// if not => insert one
|
||||||
|
|
||||||
|
// TODO: Search for padding and use that
|
||||||
|
|
||||||
|
if(d->hasXiphComment) {
|
||||||
|
|
||||||
|
long nextBlockOffset = d->flacStart;
|
||||||
|
bool isLastBlock = false;
|
||||||
|
|
||||||
|
while(!isLastBlock) {
|
||||||
|
seek(nextBlockOffset);
|
||||||
|
|
||||||
|
ByteVector header = readBlock(4);
|
||||||
|
char blockType = header[0] & 0x7f;
|
||||||
|
isLastBlock = (header[0] & 0x80) != 0;
|
||||||
|
uint blockLength = header.mid(1, 3).toUInt();
|
||||||
|
|
||||||
|
if(blockType == VorbisComment) {
|
||||||
|
data[0] = header[0];
|
||||||
|
insert(data, nextBlockOffset, blockLength + 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextBlockOffset += blockLength + 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
const long firstBlockOffset = d->flacStart;
|
||||||
|
seek(firstBlockOffset);
|
||||||
|
|
||||||
|
ByteVector header = readBlock(4);
|
||||||
|
bool isLastBlock = (header[0] & 0x80) != 0;
|
||||||
|
uint blockLength = header.mid(1, 3).toUInt();
|
||||||
|
|
||||||
|
if(isLastBlock) {
|
||||||
|
|
||||||
|
// If the first block was previously also the last block, then we want to
|
||||||
|
// mark it as no longer being the first block (the writeBlock() call) and
|
||||||
|
// then set the data for the block that we're about to write to mark our
|
||||||
|
// new block as the last block.
|
||||||
|
|
||||||
|
seek(firstBlockOffset);
|
||||||
|
writeBlock(static_cast<char>(header[0] & 0x7F));
|
||||||
|
data[0] |= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(data, firstBlockOffset + blockLength + 4, 0);
|
||||||
|
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 != StreamInfo) {
|
||||||
|
debug("FLAC::File::scan() -- invalid FLAC stream");
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->streamInfoData = readBlock(length);
|
||||||
|
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();
|
||||||
|
|
||||||
|
if(blockType == Padding) {
|
||||||
|
// debug("FLAC::File::scan() -- Padding found");
|
||||||
|
}
|
||||||
|
// Found the vorbis-comment
|
||||||
|
else if(blockType == VorbisComment) {
|
||||||
|
d->xiphCommentData = readBlock(length);
|
||||||
|
d->hasXiphComment = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
201
Frameworks/TagLib/taglib/taglib/flac/flacfile.h
Normal file
201
Frameworks/TagLib/taglib/taglib/flac/flacfile.h
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This library is distributed in the hope that it will be useful, but *
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||||
|
* Lesser General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 "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
|
||||||
|
|
||||||
|
private:
|
||||||
|
File(const File &);
|
||||||
|
File &operator=(const File &);
|
||||||
|
|
||||||
|
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||||
|
void scan();
|
||||||
|
long findID3v2();
|
||||||
|
long findID3v1();
|
||||||
|
ByteVector xiphCommentData() const;
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
150
Frameworks/TagLib/taglib/taglib/flac/flacproperties.cpp
Normal file
150
Frameworks/TagLib/taglib/taglib/flac/flacproperties.cpp
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This library is distributed in the hope that it will be useful, but *
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||||
|
* Lesser General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style)
|
||||||
|
{
|
||||||
|
d = new PropertiesPrivate(data, streamLength, style);
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
|
||||||
|
{
|
||||||
|
d = new PropertiesPrivate(file->streamInfoData(), file->streamLength(), style);
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::length() const
|
||||||
|
{
|
||||||
|
return d->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return d->bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return d->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::sampleWidth() const
|
||||||
|
{
|
||||||
|
return d->sampleWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void FLAC::Properties::read()
|
||||||
|
{
|
||||||
|
if(d->data.size() < 18) {
|
||||||
|
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
// Minimum block size (in samples)
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
// Maximum block size (in samples)
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
// Minimum frame size (in bytes)
|
||||||
|
pos += 3;
|
||||||
|
|
||||||
|
// Maximum frame size (in bytes)
|
||||||
|
pos += 3;
|
||||||
|
|
||||||
|
uint flags = d->data.mid(pos, 4).toUInt(true);
|
||||||
|
d->sampleRate = flags >> 12;
|
||||||
|
d->channels = ((flags >> 9) & 7) + 1;
|
||||||
|
d->sampleWidth = ((flags >> 4) & 31) + 1;
|
||||||
|
|
||||||
|
// The last 4 bits are the most significant 4 bits for the 36 bit
|
||||||
|
// stream length in samples. (Audio files measured in days)
|
||||||
|
|
||||||
|
uint highLength =d->sampleRate > 0 ? (((flags & 0xf) << 28) / d->sampleRate) << 4 : 0;
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
d->length = d->sampleRate > 0 ?
|
||||||
|
(d->data.mid(pos, 4).toUInt(true)) / d->sampleRate + highLength : 0;
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
// Uncompressed bitrate:
|
||||||
|
|
||||||
|
//d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth;
|
||||||
|
|
||||||
|
// Real bitrate:
|
||||||
|
|
||||||
|
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
|
||||||
|
}
|
92
Frameworks/TagLib/taglib/taglib/flac/flacproperties.h
Normal file
92
Frameworks/TagLib/taglib/taglib/flac/flacproperties.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This library is distributed in the hope that it will be useful, but *
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||||
|
* Lesser General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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;
|
||||||
|
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 = 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 genreMap();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the name of the genre at \a index in the ID3v1 genre list. If
|
||||||
|
* \a index is out of range -- less than zero or greater than 146 -- a null
|
||||||
|
* string will be returned.
|
||||||
|
*/
|
||||||
|
String genre(int index);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the genre index for the (case sensitive) genre \a name. If the
|
||||||
|
* genre is not in the list 255 (which signifies an unknown genre in ID3v1)
|
||||||
|
* will be returned.
|
||||||
|
*/
|
||||||
|
int genreIndex(const String &name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
248
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.cpp
Normal file
248
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.cpp
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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]);
|
||||||
|
}
|
180
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.h
Normal file
180
Frameworks/TagLib/taglib/taglib/mpeg/id3v1/id3v1tag.h
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 ISO-8859-1.
|
||||||
|
*
|
||||||
|
* \see ID3v1::Tag::setStringHandler()
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT StringHandler
|
||||||
|
{
|
||||||
|
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 void setTitle(const String &s);
|
||||||
|
virtual void setArtist(const String &s);
|
||||||
|
virtual void setAlbum(const String &s);
|
||||||
|
virtual void setComment(const String &s);
|
||||||
|
virtual void setGenre(const String &s);
|
||||||
|
virtual void setYear(uint i);
|
||||||
|
virtual void setTrack(uint i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the string handler that decides how the ID3v1 data will be
|
||||||
|
* converted to and from binary data.
|
||||||
|
*
|
||||||
|
* \see StringHandler
|
||||||
|
*/
|
||||||
|
static void setStringHandler(const StringHandler *handler);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
* Reads from the file specified in the constructor.
|
||||||
|
*/
|
||||||
|
void read();
|
||||||
|
/*!
|
||||||
|
* Pareses the body of the tag in \a data.
|
||||||
|
*/
|
||||||
|
void parse(const ByteVector &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tag(const Tag &);
|
||||||
|
Tag &operator=(const Tag &);
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,170 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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);
|
||||||
|
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));
|
||||||
|
}
|
|
@ -0,0 +1,220 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AttachedPictureFrame(const ByteVector &data, Header *h);
|
||||||
|
AttachedPictureFrame(const AttachedPictureFrame &);
|
||||||
|
AttachedPictureFrame &operator=(const AttachedPictureFrame &);
|
||||||
|
|
||||||
|
class AttachedPictureFramePrivate;
|
||||||
|
AttachedPictureFramePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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,174 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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.
|
||||||
|
*/
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int Footer::size()
|
||||||
|
{
|
||||||
|
return FooterPrivate::size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Footer::render(const Header *header) const
|
||||||
|
{
|
||||||
|
ByteVector headerData = header->render();
|
||||||
|
headerData[0] = '3';
|
||||||
|
headerData[1] = 'D';
|
||||||
|
headerData[2] = 'I';
|
||||||
|
return headerData;
|
||||||
|
}
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 const unsigned int size();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Renders the footer based on the data in \a header.
|
||||||
|
*/
|
||||||
|
ByteVector render(const Header *header) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Footer(const Footer &);
|
||||||
|
Footer &operator=(const Footer &);
|
||||||
|
|
||||||
|
class FooterPrivate;
|
||||||
|
FooterPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
407
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp
Normal file
407
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 "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"
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UnknownFrame(data, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::Type FrameFactory::defaultTextEncoding() const
|
||||||
|
{
|
||||||
|
return d->defaultEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameFactory::setDefaultTextEncoding(String::Type encoding)
|
||||||
|
{
|
||||||
|
d->useDefaultEncoding = true;
|
||||||
|
d->defaultEncoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FrameFactory::FrameFactory()
|
||||||
|
{
|
||||||
|
d = new FrameFactoryPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameFactory::~FrameFactory()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrameFactory::updateFrame(Frame::Header *header) const
|
||||||
|
{
|
||||||
|
TagLib::ByteVector frameID = header->frameID();
|
||||||
|
|
||||||
|
switch(header->version()) {
|
||||||
|
|
||||||
|
case 2: // ID3v2.2
|
||||||
|
{
|
||||||
|
if(frameID == "CRM" ||
|
||||||
|
frameID == "EQU" ||
|
||||||
|
frameID == "LNK" ||
|
||||||
|
frameID == "RVA" ||
|
||||||
|
frameID == "TIM" ||
|
||||||
|
frameID == "TSI")
|
||||||
|
{
|
||||||
|
debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
|
||||||
|
". It will be discarded from the tag.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of
|
||||||
|
// the frames to their 4 byte ID3v2.4 equivalent.
|
||||||
|
|
||||||
|
convertFrame("BUF", "RBUF", header);
|
||||||
|
convertFrame("CNT", "PCNT", header);
|
||||||
|
convertFrame("COM", "COMM", header);
|
||||||
|
convertFrame("CRA", "AENC", header);
|
||||||
|
convertFrame("ETC", "ETCO", header);
|
||||||
|
convertFrame("GEO", "GEOB", header);
|
||||||
|
convertFrame("IPL", "TIPL", header);
|
||||||
|
convertFrame("MCI", "MCDI", header);
|
||||||
|
convertFrame("MLL", "MLLT", header);
|
||||||
|
convertFrame("PIC", "APIC", header);
|
||||||
|
convertFrame("POP", "POPM", header);
|
||||||
|
convertFrame("REV", "RVRB", header);
|
||||||
|
convertFrame("SLT", "SYLT", header);
|
||||||
|
convertFrame("STC", "SYTC", header);
|
||||||
|
convertFrame("TAL", "TALB", header);
|
||||||
|
convertFrame("TBP", "TBPM", header);
|
||||||
|
convertFrame("TCM", "TCOM", header);
|
||||||
|
convertFrame("TCO", "TCON", header);
|
||||||
|
convertFrame("TCR", "TCOP", header);
|
||||||
|
convertFrame("TDA", "TDRC", header);
|
||||||
|
convertFrame("TDY", "TDLY", header);
|
||||||
|
convertFrame("TEN", "TENC", header);
|
||||||
|
convertFrame("TFT", "TFLT", header);
|
||||||
|
convertFrame("TKE", "TKEY", header);
|
||||||
|
convertFrame("TLA", "TLAN", header);
|
||||||
|
convertFrame("TLE", "TLEN", header);
|
||||||
|
convertFrame("TMT", "TMED", header);
|
||||||
|
convertFrame("TOA", "TOAL", header);
|
||||||
|
convertFrame("TOF", "TOFN", header);
|
||||||
|
convertFrame("TOL", "TOLY", header);
|
||||||
|
convertFrame("TOR", "TDOR", header);
|
||||||
|
convertFrame("TOT", "TOAL", header);
|
||||||
|
convertFrame("TP1", "TPE1", header);
|
||||||
|
convertFrame("TP2", "TPE2", header);
|
||||||
|
convertFrame("TP3", "TPE3", header);
|
||||||
|
convertFrame("TP4", "TPE4", header);
|
||||||
|
convertFrame("TPA", "TPOS", header);
|
||||||
|
convertFrame("TPB", "TPUB", header);
|
||||||
|
convertFrame("TRC", "TSRC", header);
|
||||||
|
convertFrame("TRD", "TDRC", header);
|
||||||
|
convertFrame("TRK", "TRCK", header);
|
||||||
|
convertFrame("TSS", "TSSE", header);
|
||||||
|
convertFrame("TT1", "TIT1", header);
|
||||||
|
convertFrame("TT2", "TIT2", header);
|
||||||
|
convertFrame("TT3", "TIT3", header);
|
||||||
|
convertFrame("TXT", "TOLY", header);
|
||||||
|
convertFrame("TXX", "TXXX", header);
|
||||||
|
convertFrame("TYE", "TDRC", header);
|
||||||
|
convertFrame("UFI", "UFID", header);
|
||||||
|
convertFrame("ULT", "USLT", header);
|
||||||
|
convertFrame("WAF", "WOAF", header);
|
||||||
|
convertFrame("WAR", "WOAR", header);
|
||||||
|
convertFrame("WAS", "WOAS", header);
|
||||||
|
convertFrame("WCM", "WCOM", header);
|
||||||
|
convertFrame("WCP", "WCOP", header);
|
||||||
|
convertFrame("WPB", "WPUB", header);
|
||||||
|
convertFrame("WXX", "WXXX", header);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3: // ID3v2.3
|
||||||
|
{
|
||||||
|
if(frameID == "EQUA" ||
|
||||||
|
frameID == "RVAD" ||
|
||||||
|
frameID == "TIME" ||
|
||||||
|
frameID == "TRDA" ||
|
||||||
|
frameID == "TSIZ" ||
|
||||||
|
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;
|
||||||
|
String s = frame->toString();
|
||||||
|
|
||||||
|
while(s.startsWith("(")) {
|
||||||
|
|
||||||
|
int closing = s.find(")");
|
||||||
|
|
||||||
|
if(closing < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fields.append(s.substr(1, closing - 1));
|
||||||
|
|
||||||
|
s = s.substr(closing + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!s.isEmpty())
|
||||||
|
fields.append(s);
|
||||||
|
|
||||||
|
if(fields.isEmpty())
|
||||||
|
fields.append(String::null);
|
||||||
|
|
||||||
|
frame->setText(fields);
|
||||||
|
}
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 TAGLIB_EXPORT 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
|
||||||
|
#include "id3v2header.h"
|
||||||
|
#include "id3v2footer.h"
|
||||||
|
#include "id3v2synchdata.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace ID3v2;
|
||||||
|
|
||||||
|
class Header::HeaderPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HeaderPrivate() : majorVersion(4),
|
||||||
|
revisionNumber(0),
|
||||||
|
unsynchronisation(false),
|
||||||
|
extendedHeader(false),
|
||||||
|
experimentalIndicator(false),
|
||||||
|
footerPresent(false),
|
||||||
|
tagSize(0) {}
|
||||||
|
|
||||||
|
~HeaderPrivate() {}
|
||||||
|
|
||||||
|
uint majorVersion;
|
||||||
|
uint revisionNumber;
|
||||||
|
|
||||||
|
bool unsynchronisation;
|
||||||
|
bool extendedHeader;
|
||||||
|
bool experimentalIndicator;
|
||||||
|
bool footerPresent;
|
||||||
|
|
||||||
|
uint tagSize;
|
||||||
|
|
||||||
|
static const uint size = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
TagLib::uint Header::size()
|
||||||
|
{
|
||||||
|
return HeaderPrivate::size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Header::fileIdentifier()
|
||||||
|
{
|
||||||
|
return ByteVector::fromCString("ID3");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Header::Header()
|
||||||
|
{
|
||||||
|
d = new HeaderPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Header::Header(const ByteVector &data)
|
||||||
|
{
|
||||||
|
d = new HeaderPrivate;
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Header::~Header()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Header::majorVersion() const
|
||||||
|
{
|
||||||
|
return d->majorVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Header::setMajorVersion(TagLib::uint version)
|
||||||
|
{
|
||||||
|
d->majorVersion = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Header::revisionNumber() const
|
||||||
|
{
|
||||||
|
return d->revisionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Header::unsynchronisation() const
|
||||||
|
{
|
||||||
|
return d->unsynchronisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Header::extendedHeader() const
|
||||||
|
{
|
||||||
|
return d->extendedHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Header::experimentalIndicator() const
|
||||||
|
{
|
||||||
|
return d->experimentalIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Header::footerPresent() const
|
||||||
|
{
|
||||||
|
return d->footerPresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Header::tagSize() const
|
||||||
|
{
|
||||||
|
return d->tagSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Header::completeTagSize() const
|
||||||
|
{
|
||||||
|
if(d->footerPresent)
|
||||||
|
return d->tagSize + d->size + Footer::size();
|
||||||
|
else
|
||||||
|
return d->tagSize + d->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Header::setTagSize(uint s)
|
||||||
|
{
|
||||||
|
d->tagSize = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Header::setData(const ByteVector &data)
|
||||||
|
{
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Header::render() const
|
||||||
|
{
|
||||||
|
ByteVector v;
|
||||||
|
|
||||||
|
// add the file identifier -- "ID3"
|
||||||
|
v.append(fileIdentifier());
|
||||||
|
|
||||||
|
// add the version number -- we always render a 2.4.0 tag regardless of what
|
||||||
|
// the tag originally was.
|
||||||
|
|
||||||
|
v.append(char(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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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,63 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "id3v2synchdata.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace ID3v2;
|
||||||
|
|
||||||
|
TagLib::uint SynchData::toUInt(const ByteVector &data)
|
||||||
|
{
|
||||||
|
uint sum = 0;
|
||||||
|
int last = data.size() > 4 ? 3 : data.size() - 1;
|
||||||
|
|
||||||
|
for(int i = 0; i <= last; i++)
|
||||||
|
sum |= (data[i] & 0x7f) << ((last - i) * 7);
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector SynchData::fromUInt(uint value)
|
||||||
|
{
|
||||||
|
ByteVector v(4, 0);
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; i++)
|
||||||
|
v[i] = uchar(value >> ((3 - i) * 7) & 0x7f);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
474
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.cpp
Normal file
474
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.cpp
Normal file
|
@ -0,0 +1,474 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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)
|
||||||
|
{
|
||||||
|
if(static_cast<CommentsFrame *>(*it)->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) {
|
||||||
|
|
||||||
|
bool isNumber = true;
|
||||||
|
|
||||||
|
for(String::ConstIterator charIt = (*it).begin();
|
||||||
|
isNumber && charIt != (*it).end();
|
||||||
|
++charIt)
|
||||||
|
{
|
||||||
|
isNumber = *charIt >= '0' && *charIt <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isNumber) {
|
||||||
|
int number = (*it).toInt();
|
||||||
|
if(number >= 0 && number <= 255)
|
||||||
|
*it = ID3v1::genre(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(std::find(genres.begin(), genres.end(), *it) == genres.end())
|
||||||
|
genres.append(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return genres.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint ID3v2::Tag::year() const
|
||||||
|
{
|
||||||
|
if(!d->frameListMap["TDRC"].isEmpty())
|
||||||
|
return d->frameListMap["TDRC"].front()->toString().substr(0, 4).toInt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint ID3v2::Tag::track() const
|
||||||
|
{
|
||||||
|
if(!d->frameListMap["TRCK"].isEmpty())
|
||||||
|
return d->frameListMap["TRCK"].front()->toString().toInt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setTitle(const String &s)
|
||||||
|
{
|
||||||
|
setTextFrame("TIT2", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setArtist(const String &s)
|
||||||
|
{
|
||||||
|
setTextFrame("TPE1", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setAlbum(const String &s)
|
||||||
|
{
|
||||||
|
setTextFrame("TALB", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setComment(const String &s)
|
||||||
|
{
|
||||||
|
if(s.isEmpty()) {
|
||||||
|
removeFrames("COMM");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!d->frameListMap["COMM"].isEmpty())
|
||||||
|
d->frameListMap["COMM"].front()->setText(s);
|
||||||
|
else {
|
||||||
|
CommentsFrame *f = new CommentsFrame(d->factory->defaultTextEncoding());
|
||||||
|
addFrame(f);
|
||||||
|
f->setText(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setGenre(const String &s)
|
||||||
|
{
|
||||||
|
if(s.isEmpty()) {
|
||||||
|
removeFrames("TCON");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iTunes can't handle correctly encoded ID3v2.4 numerical genres. Just use
|
||||||
|
// strings until iTunes sucks less.
|
||||||
|
|
||||||
|
#ifdef NO_ITUNES_HACKS
|
||||||
|
|
||||||
|
int index = ID3v1::genreIndex(s);
|
||||||
|
|
||||||
|
if(index != 255)
|
||||||
|
setTextFrame("TCON", String::number(index));
|
||||||
|
else
|
||||||
|
setTextFrame("TCON", s);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
setTextFrame("TCON", s);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setYear(uint i)
|
||||||
|
{
|
||||||
|
if(i <= 0) {
|
||||||
|
removeFrames("TDRC");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTextFrame("TDRC", String::number(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setTrack(uint i)
|
||||||
|
{
|
||||||
|
if(i <= 0) {
|
||||||
|
removeFrames("TRCK");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTextFrame("TRCK", String::number(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ID3v2::Tag::isEmpty() const
|
||||||
|
{
|
||||||
|
return d->frameList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Header *ID3v2::Tag::header() const
|
||||||
|
{
|
||||||
|
return &(d->header);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedHeader *ID3v2::Tag::extendedHeader() const
|
||||||
|
{
|
||||||
|
return d->extendedHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
Footer *ID3v2::Tag::footer() const
|
||||||
|
{
|
||||||
|
return d->footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrameListMap &ID3v2::Tag::frameListMap() const
|
||||||
|
{
|
||||||
|
return d->frameListMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrameList &ID3v2::Tag::frameList() const
|
||||||
|
{
|
||||||
|
return d->frameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrameList &ID3v2::Tag::frameList(const ByteVector &frameID) const
|
||||||
|
{
|
||||||
|
return d->frameListMap[frameID];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::addFrame(Frame *frame)
|
||||||
|
{
|
||||||
|
d->frameList.append(frame);
|
||||||
|
d->frameListMap[frame->frameID()].append(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::removeFrame(Frame *frame, bool del)
|
||||||
|
{
|
||||||
|
// remove the frame from the frame list
|
||||||
|
FrameList::Iterator it = d->frameList.find(frame);
|
||||||
|
d->frameList.erase(it);
|
||||||
|
|
||||||
|
// ...and from the frame list map
|
||||||
|
it = d->frameListMap[frame->frameID()].find(frame);
|
||||||
|
d->frameListMap[frame->frameID()].erase(it);
|
||||||
|
|
||||||
|
// ...and delete as desired
|
||||||
|
if(del)
|
||||||
|
delete frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::removeFrames(const ByteVector &id)
|
||||||
|
{
|
||||||
|
FrameList l = d->frameListMap[id];
|
||||||
|
for(FrameList::Iterator it = l.begin(); it != l.end(); ++it)
|
||||||
|
removeFrame(*it, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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()->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);
|
||||||
|
}
|
||||||
|
}
|
300
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.h
Normal file
300
Frameworks/TagLib/taglib/taglib/mpeg/id3v2/id3v2tag.h
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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;
|
||||||
|
|
||||||
|
virtual void setTitle(const String &s);
|
||||||
|
virtual void setArtist(const String &s);
|
||||||
|
virtual void setAlbum(const String &s);
|
||||||
|
virtual void setComment(const String &s);
|
||||||
|
virtual void setGenre(const String &s);
|
||||||
|
virtual void setYear(uint i);
|
||||||
|
virtual void setTrack(uint i);
|
||||||
|
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the tag's header.
|
||||||
|
*/
|
||||||
|
Header *header() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the tag's extended header or null if there is no
|
||||||
|
* extended header.
|
||||||
|
*/
|
||||||
|
ExtendedHeader *extendedHeader() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the tag's footer or null if there is no footer.
|
||||||
|
*
|
||||||
|
* \deprecated I don't see any reason to keep this around since there's
|
||||||
|
* nothing useful to be retrieved from the footer, but well, again, I'm
|
||||||
|
* prone to change my mind, so this gets to stay around until near a
|
||||||
|
* release.
|
||||||
|
*/
|
||||||
|
Footer *footer() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a reference to the frame list map. This is an FrameListMap of
|
||||||
|
* all of the frames in the tag.
|
||||||
|
*
|
||||||
|
* This is the most convenient structure for accessing the tag's frames.
|
||||||
|
* Many frame types allow multiple instances of the same frame type so this
|
||||||
|
* is a map of lists. In most cases however there will only be a single
|
||||||
|
* frame of a certain type.
|
||||||
|
*
|
||||||
|
* Let's say for instance that you wanted to access the frame for total
|
||||||
|
* beats per minute -- the TBPM frame.
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* TagLib::MPEG::File f("foo.mp3");
|
||||||
|
*
|
||||||
|
* // Check to make sure that it has an ID3v2 tag
|
||||||
|
*
|
||||||
|
* if(f.ID3v2Tag()) {
|
||||||
|
*
|
||||||
|
* // Get the list of frames for a specific frame type
|
||||||
|
*
|
||||||
|
* TagLib::ID3v2::FrameList l = f.ID3v2Tag()->frameListMap()["TBPM"];
|
||||||
|
*
|
||||||
|
* if(!l.isEmpty())
|
||||||
|
* std::cout << l.front()->toString() << std::endl;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \warning You should not modify this data structure directly, instead
|
||||||
|
* use addFrame() and removeFrame().
|
||||||
|
*
|
||||||
|
* \see frameList()
|
||||||
|
*/
|
||||||
|
const FrameListMap &frameListMap() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a reference to the frame list. This is an FrameList of all of
|
||||||
|
* the frames in the tag in the order that they were parsed.
|
||||||
|
*
|
||||||
|
* This can be useful if for example you want iterate over the tag's frames
|
||||||
|
* in the order that they occur in the tag.
|
||||||
|
*
|
||||||
|
* \warning You should not modify this data structure directly, instead
|
||||||
|
* use addFrame() and removeFrame().
|
||||||
|
*/
|
||||||
|
const FrameList &frameList() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the frame list for frames with the id \a frameID or an empty
|
||||||
|
* list if there are no frames of that type. This is just a convenience
|
||||||
|
* and is equivalent to:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* frameListMap()[frameID];
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \see frameListMap()
|
||||||
|
*/
|
||||||
|
const FrameList &frameList(const ByteVector &frameID) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Add a frame to the tag. At this point the tag takes ownership of
|
||||||
|
* the frame and will handle freeing its memory.
|
||||||
|
*
|
||||||
|
* \note Using this method will invalidate any pointers on the list
|
||||||
|
* returned by frameList()
|
||||||
|
*/
|
||||||
|
void addFrame(Frame *frame);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Remove a frame from the tag. If \a del is true the frame's memory
|
||||||
|
* will be freed; if it is false, it must be deleted by the user.
|
||||||
|
*
|
||||||
|
* \note Using this method will invalidate any pointers on the list
|
||||||
|
* returned by frameList()
|
||||||
|
*/
|
||||||
|
void removeFrame(Frame *frame, bool del = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Remove all frames of type \a id from the tag and free their memory.
|
||||||
|
*
|
||||||
|
* \note Using this method will invalidate any pointers on the list
|
||||||
|
* returned by frameList()
|
||||||
|
*/
|
||||||
|
void removeFrames(const ByteVector &id);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Render the tag back to binary data, suitable to be written to disk.
|
||||||
|
*/
|
||||||
|
ByteVector render() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
* Reads data from the file specified in the constructor. It does basic
|
||||||
|
* parsing of the data in the largest chunks. It partitions the tag into
|
||||||
|
* the Header, the body of the tag (which contains the ExtendedHeader and
|
||||||
|
* frames) and Footer.
|
||||||
|
*/
|
||||||
|
void read();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This is called by read to parse the body of the tag. It determines if an
|
||||||
|
* extended header exists and adds frames to the FrameListMap.
|
||||||
|
*/
|
||||||
|
void parse(const ByteVector &data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the value of the text frame with the Frame ID \a id to \a value.
|
||||||
|
* If the frame does not exist, it is created.
|
||||||
|
*/
|
||||||
|
void setTextFrame(const ByteVector &id, const String &value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tag(const Tag &);
|
||||||
|
Tag &operator=(const Tag &);
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 mactch MPEG synch.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::bitset<32> flags(data.toUInt());
|
||||||
|
|
||||||
|
// Check for the second byte's part of the MPEG synch
|
||||||
|
|
||||||
|
if(!flags[23] || !flags[22] || !flags[21]) {
|
||||||
|
debug("MPEG::Header::parse() -- Second byte did not mactch MPEG synch.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the MPEG version
|
||||||
|
|
||||||
|
if(!flags[20] && !flags[19])
|
||||||
|
d->version = Version2_5;
|
||||||
|
else if(flags[20] && !flags[19])
|
||||||
|
d->version = Version2;
|
||||||
|
else if(flags[20] && flags[19])
|
||||||
|
d->version = Version1;
|
||||||
|
|
||||||
|
// Set the MPEG layer
|
||||||
|
|
||||||
|
if(!flags[18] && flags[17])
|
||||||
|
d->layer = 3;
|
||||||
|
else if(flags[18] && !flags[17])
|
||||||
|
d->layer = 2;
|
||||||
|
else if(flags[18] && flags[17])
|
||||||
|
d->layer = 1;
|
||||||
|
|
||||||
|
d->protectionEnabled = !flags[16];
|
||||||
|
|
||||||
|
// Set the bitrate
|
||||||
|
|
||||||
|
static const int bitrates[2][3][16] = {
|
||||||
|
{ // Version 1
|
||||||
|
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1
|
||||||
|
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // layer 2
|
||||||
|
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3
|
||||||
|
},
|
||||||
|
{ // Version 2 or 2.5
|
||||||
|
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1
|
||||||
|
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2
|
||||||
|
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } // layer 3
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const int versionIndex = d->version == Version1 ? 0 : 1;
|
||||||
|
const int layerIndex = d->layer > 0 ? d->layer - 1 : 0;
|
||||||
|
|
||||||
|
// The bitrate index is encoded as the first 4 bits of the 3rd byte,
|
||||||
|
// i.e. 1111xxxx
|
||||||
|
|
||||||
|
int i = uchar(data[2]) >> 4;
|
||||||
|
|
||||||
|
d->bitrate = bitrates[versionIndex][layerIndex][i];
|
||||||
|
|
||||||
|
// Set the sample rate
|
||||||
|
|
||||||
|
static const int sampleRates[3][4] = {
|
||||||
|
{ 44100, 48000, 32000, 0 }, // Version 1
|
||||||
|
{ 22050, 24000, 16000, 0 }, // Version 2
|
||||||
|
{ 11025, 12000, 8000, 0 } // Version 2.5
|
||||||
|
};
|
||||||
|
|
||||||
|
// The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx
|
||||||
|
|
||||||
|
i = uchar(data[2]) >> 2 & 0x03;
|
||||||
|
|
||||||
|
d->sampleRate = sampleRates[d->version][i];
|
||||||
|
|
||||||
|
if(d->sampleRate == 0) {
|
||||||
|
debug("MPEG::Header::parse() -- Invalid sample rate.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The channel mode is encoded as a 2 bit value at the end of the 3nd byte,
|
||||||
|
// i.e. xxxxxx11
|
||||||
|
|
||||||
|
d->channelMode = ChannelMode((uchar(data[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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
252
Frameworks/TagLib/taglib/taglib/mpeg/mpegproperties.cpp
Normal file
252
Frameworks/TagLib/taglib/taglib/mpeg/mpegproperties.cpp
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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();
|
||||||
|
|
||||||
|
d->length = int(timePerFrame * d->xingHeader->totalFrames());
|
||||||
|
d->bitrate = d->length > 0 ? d->xingHeader->totalSize() * 8 / d->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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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();
|
||||||
|
|
||||||
|
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
336
Frameworks/TagLib/taglib/taglib/ogg/oggfile.cpp
Normal file
336
Frameworks/TagLib/taglib/taglib/ogg/oggfile.cpp
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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> &pageGroup)
|
||||||
|
{
|
||||||
|
if(pageGroup.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ByteVectorList packets;
|
||||||
|
|
||||||
|
// If the first page of the group isn't dirty, append its partial content here.
|
||||||
|
|
||||||
|
if(!d->dirtyPages.contains(d->pages[pageGroup.front()]->firstPacketIndex()))
|
||||||
|
packets.append(d->pages[pageGroup.front()]->packets().front());
|
||||||
|
|
||||||
|
int previousPacket = -1;
|
||||||
|
int originalSize = 0;
|
||||||
|
|
||||||
|
for(List<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);
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
for(List<Page *>::ConstIterator it = pages.begin(); it != pages.end(); ++it) {
|
||||||
|
const int index = (*it)->header()->pageSequenceNumber();
|
||||||
|
delete d->pages[index];
|
||||||
|
d->pages[index] = *it;
|
||||||
|
}
|
||||||
|
}
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
256
Frameworks/TagLib/taglib/taglib/ogg/oggpage.cpp
Normal file
256
Frameworks/TagLib/taglib/taglib/ogg/oggpage.cpp
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 the page is (a) the first page and it's complete or (b) the last page
|
||||||
|
// and it's complete or (c) a page in the middle.
|
||||||
|
|
||||||
|
else if((flags & BeginsWithPacket && !d->header.firstPacketContinued()) ||
|
||||||
|
(flags & EndsWithPacket && d->header.lastPacketCompleted()) ||
|
||||||
|
(!(flags & BeginsWithPacket) && !(flags & EndsWithPacket)))
|
||||||
|
{
|
||||||
|
flags = ContainsPacketFlags(flags | CompletePacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Ogg::Page::packetCount() const
|
||||||
|
{
|
||||||
|
return d->header.packetSizes().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVectorList Ogg::Page::packets() const
|
||||||
|
{
|
||||||
|
if(!d->packets.isEmpty())
|
||||||
|
return d->packets;
|
||||||
|
|
||||||
|
ByteVectorList l;
|
||||||
|
|
||||||
|
if(d->file && d->header.isValid()) {
|
||||||
|
|
||||||
|
d->file->seek(d->packetOffset);
|
||||||
|
|
||||||
|
List<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();
|
||||||
|
|
||||||
|
if(strategy == Repaginate || totalSize + packets.size() > 255 * 256) {
|
||||||
|
debug("Ogg::Page::paginate() -- Sorry! Repagination is not yet implemented.");
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle creation of multiple pages here with appropriate pagination.
|
||||||
|
|
||||||
|
Page *p = new Page(packets, streamSerialNumber, firstPage, firstPacketContinued,
|
||||||
|
lastPacketCompleted, containsLastPacket);
|
||||||
|
l.append(p);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Ogg::Page::Page(const ByteVectorList &packets,
|
||||||
|
uint streamSerialNumber,
|
||||||
|
int pageNumber,
|
||||||
|
bool firstPacketContinued,
|
||||||
|
bool lastPacketCompleted,
|
||||||
|
bool containsLastPacket)
|
||||||
|
{
|
||||||
|
d = new PagePrivate;
|
||||||
|
|
||||||
|
ByteVector data;
|
||||||
|
List<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);
|
||||||
|
}
|
203
Frameworks/TagLib/taglib/taglib/ogg/oggpage.h
Normal file
203
Frameworks/TagLib/taglib/taglib/ogg/oggpage.h
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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
|
313
Frameworks/TagLib/taglib/taglib/ogg/xiphcomment.cpp
Normal file
313
Frameworks/TagLib/taglib/taglib/ogg/xiphcomment.cpp
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tbytevector.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
|
||||||
|
#include <xiphcomment.h>
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class Ogg::XiphComment::XiphCommentPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FieldListMap fieldListMap;
|
||||||
|
String vendorID;
|
||||||
|
String commentField;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Ogg::XiphComment::XiphComment() : TagLib::Tag()
|
||||||
|
{
|
||||||
|
d = new XiphCommentPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogg::XiphComment::XiphComment(const ByteVector &data) : TagLib::Tag()
|
||||||
|
{
|
||||||
|
d = new XiphCommentPrivate;
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogg::XiphComment::~XiphComment()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::title() const
|
||||||
|
{
|
||||||
|
if(d->fieldListMap["TITLE"].isEmpty())
|
||||||
|
return String::null;
|
||||||
|
return d->fieldListMap["TITLE"].front();
|
||||||
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::artist() const
|
||||||
|
{
|
||||||
|
if(d->fieldListMap["ARTIST"].isEmpty())
|
||||||
|
return String::null;
|
||||||
|
return d->fieldListMap["ARTIST"].front();
|
||||||
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::album() const
|
||||||
|
{
|
||||||
|
if(d->fieldListMap["ALBUM"].isEmpty())
|
||||||
|
return String::null;
|
||||||
|
return d->fieldListMap["ALBUM"].front();
|
||||||
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::comment() const
|
||||||
|
{
|
||||||
|
if(!d->fieldListMap["DESCRIPTION"].isEmpty()) {
|
||||||
|
d->commentField = "DESCRIPTION";
|
||||||
|
return d->fieldListMap["DESCRIPTION"].front();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!d->fieldListMap["COMMENT"].isEmpty()) {
|
||||||
|
d->commentField = "COMMENT";
|
||||||
|
return d->fieldListMap["COMMENT"].front();
|
||||||
|
}
|
||||||
|
|
||||||
|
return String::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::genre() const
|
||||||
|
{
|
||||||
|
if(d->fieldListMap["GENRE"].isEmpty())
|
||||||
|
return String::null;
|
||||||
|
return d->fieldListMap["GENRE"].front();
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Ogg::XiphComment::year() const
|
||||||
|
{
|
||||||
|
if(d->fieldListMap["DATE"].isEmpty())
|
||||||
|
return 0;
|
||||||
|
return d->fieldListMap["DATE"].front().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Ogg::XiphComment::track() const
|
||||||
|
{
|
||||||
|
if(d->fieldListMap["TRACKNUMBER"].isEmpty())
|
||||||
|
return 0;
|
||||||
|
return d->fieldListMap["TRACKNUMBER"].front().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setTitle(const String &s)
|
||||||
|
{
|
||||||
|
addField("TITLE", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setArtist(const String &s)
|
||||||
|
{
|
||||||
|
addField("ARTIST", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setAlbum(const String &s)
|
||||||
|
{
|
||||||
|
addField("ALBUM", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setComment(const String &s)
|
||||||
|
{
|
||||||
|
addField(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setGenre(const String &s)
|
||||||
|
{
|
||||||
|
addField("GENRE", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setYear(uint i)
|
||||||
|
{
|
||||||
|
if(i == 0)
|
||||||
|
removeField("DATE");
|
||||||
|
else
|
||||||
|
addField("DATE", String::number(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setTrack(uint i)
|
||||||
|
{
|
||||||
|
if(i == 0)
|
||||||
|
removeField("TRACKNUMBER");
|
||||||
|
else
|
||||||
|
addField("TRACKNUMBER", String::number(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Ogg::XiphComment::isEmpty() const
|
||||||
|
{
|
||||||
|
FieldListMap::ConstIterator it = d->fieldListMap.begin();
|
||||||
|
for(; it != d->fieldListMap.end(); ++it)
|
||||||
|
if(!(*it).second.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint Ogg::XiphComment::fieldCount() const
|
||||||
|
{
|
||||||
|
uint count = 0;
|
||||||
|
|
||||||
|
FieldListMap::ConstIterator it = d->fieldListMap.begin();
|
||||||
|
for(; it != d->fieldListMap.end(); ++it)
|
||||||
|
count += (*it).second.size();
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Ogg::FieldListMap &Ogg::XiphComment::fieldListMap() const
|
||||||
|
{
|
||||||
|
return d->fieldListMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::vendorID() const
|
||||||
|
{
|
||||||
|
return d->vendorID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::addField(const String &key, const String &value, bool replace)
|
||||||
|
{
|
||||||
|
if(replace)
|
||||||
|
removeField(key.upper());
|
||||||
|
|
||||||
|
if(!key.isEmpty() && !value.isEmpty())
|
||||||
|
d->fieldListMap[key.upper()].append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::removeField(const String &key, const String &value)
|
||||||
|
{
|
||||||
|
if(!value.isNull()) {
|
||||||
|
StringList::Iterator it = d->fieldListMap[key].begin();
|
||||||
|
while(it != d->fieldListMap[key].end()) {
|
||||||
|
if(value == *it)
|
||||||
|
it = d->fieldListMap[key].erase(it);
|
||||||
|
else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d->fieldListMap.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Ogg::XiphComment::contains(const String &key) const
|
||||||
|
{
|
||||||
|
return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Ogg::XiphComment::render() const
|
||||||
|
{
|
||||||
|
return render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector Ogg::XiphComment::render(bool addFramingBit) const
|
||||||
|
{
|
||||||
|
ByteVector data;
|
||||||
|
|
||||||
|
// Add the vendor ID length and the vendor ID. It's important to use the
|
||||||
|
// length of the data(String::UTF8) rather than the length of the the string
|
||||||
|
// since this is UTF8 text and there may be more characters in the data than
|
||||||
|
// in the UTF16 string.
|
||||||
|
|
||||||
|
ByteVector vendorData = d->vendorID.data(String::UTF8);
|
||||||
|
|
||||||
|
data.append(ByteVector::fromUInt(vendorData.size(), false));
|
||||||
|
data.append(vendorData);
|
||||||
|
|
||||||
|
// Add the number of fields.
|
||||||
|
|
||||||
|
data.append(ByteVector::fromUInt(fieldCount(), false));
|
||||||
|
|
||||||
|
// Iterate over the the field lists. Our iterator returns a
|
||||||
|
// std::pair<String, StringList> where the first String is the field name and
|
||||||
|
// the StringList is the values associated with that field.
|
||||||
|
|
||||||
|
FieldListMap::ConstIterator it = d->fieldListMap.begin();
|
||||||
|
for(; it != d->fieldListMap.end(); ++it) {
|
||||||
|
|
||||||
|
// And now iterate over the values of the current list.
|
||||||
|
|
||||||
|
String fieldName = (*it).first;
|
||||||
|
StringList values = (*it).second;
|
||||||
|
|
||||||
|
StringList::ConstIterator valuesIt = values.begin();
|
||||||
|
for(; valuesIt != values.end(); ++valuesIt) {
|
||||||
|
ByteVector fieldData = fieldName.data(String::UTF8);
|
||||||
|
fieldData.append('=');
|
||||||
|
fieldData.append((*valuesIt).data(String::UTF8));
|
||||||
|
|
||||||
|
data.append(ByteVector::fromUInt(fieldData.size(), false));
|
||||||
|
data.append(fieldData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the "framing bit".
|
||||||
|
|
||||||
|
if(addFramingBit)
|
||||||
|
data.append(char(1));
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Ogg::XiphComment::parse(const ByteVector &data)
|
||||||
|
{
|
||||||
|
// The first thing in the comment data is the vendor ID length, followed by a
|
||||||
|
// UTF8 string with the vendor ID.
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
int vendorLength = data.mid(0, 4).toUInt(false);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
d->vendorID = String(data.mid(pos, vendorLength), String::UTF8);
|
||||||
|
pos += vendorLength;
|
||||||
|
|
||||||
|
// Next the number of fields in the comment vector.
|
||||||
|
|
||||||
|
int commentFields = data.mid(pos, 4).toUInt(false);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
for(int i = 0; i < commentFields; i++) {
|
||||||
|
|
||||||
|
// Each comment field is in the format "KEY=value" in a UTF8 string and has
|
||||||
|
// 4 bytes before the text starts that gives the length.
|
||||||
|
|
||||||
|
int commentLength = data.mid(pos, 4).toUInt(false);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
String comment = String(data.mid(pos, commentLength), String::UTF8);
|
||||||
|
pos += commentLength;
|
||||||
|
|
||||||
|
int commentSeparatorPosition = comment.find("=");
|
||||||
|
|
||||||
|
String key = comment.substr(0, commentSeparatorPosition);
|
||||||
|
String value = comment.substr(commentSeparatorPosition + 1);
|
||||||
|
|
||||||
|
addField(key, value, false);
|
||||||
|
}
|
||||||
|
}
|
202
Frameworks/TagLib/taglib/taglib/ogg/xiphcomment.h
Normal file
202
Frameworks/TagLib/taglib/taglib/ogg/xiphcomment.h
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_VORBISCOMMENT_H
|
||||||
|
#define TAGLIB_VORBISCOMMENT_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "tmap.h"
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "tstringlist.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace Ogg {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* A mapping between a list of field names, or keys, and a list of values
|
||||||
|
* associated with that field.
|
||||||
|
*
|
||||||
|
* \see XiphComment::fieldListMap()
|
||||||
|
*/
|
||||||
|
typedef Map<String, StringList> FieldListMap;
|
||||||
|
|
||||||
|
//! Ogg Vorbis comment implementation
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This class is an implementation of the Ogg Vorbis comment specification,
|
||||||
|
* to be found in section 5 of the Ogg Vorbis specification. Because this
|
||||||
|
* format is also used in other (currently unsupported) Xiph.org formats, it
|
||||||
|
* has been made part of a generic implementation rather than being limited
|
||||||
|
* to strictly Vorbis.
|
||||||
|
*
|
||||||
|
* Vorbis comments are a simple vector of keys and values, called fields.
|
||||||
|
* Multiple values for a given key are supported.
|
||||||
|
*
|
||||||
|
* \see fieldListMap()
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT XiphComment : public TagLib::Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Constructs an empty Vorbis comment.
|
||||||
|
*/
|
||||||
|
XiphComment();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a Vorbis comment from \a data.
|
||||||
|
*/
|
||||||
|
XiphComment(const ByteVector &data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the XiphComment.
|
||||||
|
*/
|
||||||
|
virtual ~XiphComment();
|
||||||
|
|
||||||
|
virtual String title() const;
|
||||||
|
virtual String artist() const;
|
||||||
|
virtual String album() const;
|
||||||
|
virtual String comment() const;
|
||||||
|
virtual String genre() const;
|
||||||
|
virtual uint year() const;
|
||||||
|
virtual uint track() const;
|
||||||
|
|
||||||
|
virtual void setTitle(const String &s);
|
||||||
|
virtual void setArtist(const String &s);
|
||||||
|
virtual void setAlbum(const String &s);
|
||||||
|
virtual void setComment(const String &s);
|
||||||
|
virtual void setGenre(const String &s);
|
||||||
|
virtual void setYear(uint i);
|
||||||
|
virtual void setTrack(uint i);
|
||||||
|
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of fields present in the comment.
|
||||||
|
*/
|
||||||
|
uint fieldCount() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a reference to the map of field lists. Because Xiph comments
|
||||||
|
* support multiple fields with the same key, a pure Map would not work.
|
||||||
|
* As such this is a Map of string lists, keyed on the comment field name.
|
||||||
|
*
|
||||||
|
* The standard set of Xiph/Vorbis fields (which may or may not be
|
||||||
|
* contained in any specific comment) is:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>TITLE</li>
|
||||||
|
* <li>VERSION</li>
|
||||||
|
* <li>ALBUM</li>
|
||||||
|
* <li>ARTIST</li>
|
||||||
|
* <li>PERFORMER</li>
|
||||||
|
* <li>COPYRIGHT</li>
|
||||||
|
* <li>ORGANIZATION</li>
|
||||||
|
* <li>DESCRIPTION</li>
|
||||||
|
* <li>GENRE</li>
|
||||||
|
* <li>DATE</li>
|
||||||
|
* <li>LOCATION</li>
|
||||||
|
* <li>CONTACT</li>
|
||||||
|
* <li>ISRC</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* For a more detailed description of these fields, please see the Ogg
|
||||||
|
* Vorbis specification, section 5.2.2.1.
|
||||||
|
*
|
||||||
|
* \note The Ogg Vorbis comment specification does allow these key values
|
||||||
|
* to be either upper or lower case. However, it is conventional for them
|
||||||
|
* to be upper case. As such, TagLib, when parsing a Xiph/Vorbis comment,
|
||||||
|
* converts all fields to uppercase. When you are using this data
|
||||||
|
* structure, you will need to specify the field name in upper case.
|
||||||
|
*
|
||||||
|
* \warning You should not modify this data structure directly, instead
|
||||||
|
* use addField() and removeField().
|
||||||
|
*/
|
||||||
|
const FieldListMap &fieldListMap() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the vendor ID of the Ogg Vorbis encoder. libvorbis 1.0 as the
|
||||||
|
* most common case always returns "Xiph.Org libVorbis I 20020717".
|
||||||
|
*/
|
||||||
|
String vendorID() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Add the field specified by \a key with the data \a value. If \a replace
|
||||||
|
* is true, then all of the other fields with the same key will be removed
|
||||||
|
* first.
|
||||||
|
*
|
||||||
|
* If the field value is empty, the field will be removed.
|
||||||
|
*/
|
||||||
|
void addField(const String &key, const String &value, bool replace = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Remove the field specified by \a key with the data \a value. If
|
||||||
|
* \a value is null, all of the fields with the given key will be removed.
|
||||||
|
*/
|
||||||
|
void removeField(const String &key, const String &value = String::null);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the field is contained within the comment.
|
||||||
|
*
|
||||||
|
* \note This is safer than checking for membership in the FieldListMap.
|
||||||
|
*/
|
||||||
|
bool contains(const String &key) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Renders the comment to a ByteVector suitable for inserting into a file.
|
||||||
|
*/
|
||||||
|
ByteVector render() const; // BIC: remove and merge with below
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Renders the comment to a ByteVector suitable for inserting into a file.
|
||||||
|
*
|
||||||
|
* If \a addFramingBit is true the standard Vorbis comment framing bit will
|
||||||
|
* be appended. However some formats (notably FLAC) do not work with this
|
||||||
|
* in place.
|
||||||
|
*/
|
||||||
|
ByteVector render(bool addFramingBit) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
* Reads the tag from the file specified in the constructor and fills the
|
||||||
|
* FieldListMap.
|
||||||
|
*/
|
||||||
|
void parse(const ByteVector &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
XiphComment(const XiphComment &);
|
||||||
|
XiphComment &operator=(const XiphComment &);
|
||||||
|
|
||||||
|
class XiphCommentPrivate;
|
||||||
|
XiphCommentPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
83
Frameworks/TagLib/taglib/taglib/tag.cpp
Normal file
83
Frameworks/TagLib/taglib/taglib/tag.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class Tag::TagPrivate
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Tag::Tag()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag::~Tag()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tag::isEmpty() const
|
||||||
|
{
|
||||||
|
return (title().isEmpty() &&
|
||||||
|
artist().isEmpty() &&
|
||||||
|
album().isEmpty() &&
|
||||||
|
comment().isEmpty() &&
|
||||||
|
genre().isEmpty() &&
|
||||||
|
year() == 0 &&
|
||||||
|
track() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tag::duplicate(const Tag *source, Tag *target, bool overwrite) // static
|
||||||
|
{
|
||||||
|
if(overwrite) {
|
||||||
|
target->setTitle(source->title());
|
||||||
|
target->setArtist(source->artist());
|
||||||
|
target->setAlbum(source->album());
|
||||||
|
target->setComment(source->comment());
|
||||||
|
target->setGenre(source->genre());
|
||||||
|
target->setYear(source->year());
|
||||||
|
target->setTrack(source->track());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(target->title().isEmpty())
|
||||||
|
target->setTitle(source->title());
|
||||||
|
if(target->artist().isEmpty())
|
||||||
|
target->setArtist(source->artist());
|
||||||
|
if(target->album().isEmpty())
|
||||||
|
target->setAlbum(source->album());
|
||||||
|
if(target->comment().isEmpty())
|
||||||
|
target->setComment(source->comment());
|
||||||
|
if(target->genre().isEmpty())
|
||||||
|
target->setGenre(source->genre());
|
||||||
|
if(target->year() <= 0)
|
||||||
|
target->setYear(source->year());
|
||||||
|
if(target->track() <= 0)
|
||||||
|
target->setTrack(source->track());
|
||||||
|
}
|
||||||
|
}
|
173
Frameworks/TagLib/taglib/taglib/tag.h
Normal file
173
Frameworks/TagLib/taglib/taglib/tag.h
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_TAG_H
|
||||||
|
#define TAGLIB_TAG_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "tstring.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
//! A simple, generic interface to common audio meta data fields
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This is an attempt to abstract away the difference in the meta data formats
|
||||||
|
* of various audio codecs and tagging schemes. As such it is generally a
|
||||||
|
* subset of what is available in the specific formats but should be suitable
|
||||||
|
* for most applications. This is meant to compliment the generic APIs found
|
||||||
|
* in TagLib::AudioProperties, TagLib::File and TagLib::FileRef.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Detroys this Tag instance.
|
||||||
|
*/
|
||||||
|
virtual ~Tag();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track name; if no track name is present in the tag
|
||||||
|
* String::null will be returned.
|
||||||
|
*/
|
||||||
|
virtual String title() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the artist name; if no artist name is present in the tag
|
||||||
|
* String::null will be returned.
|
||||||
|
*/
|
||||||
|
virtual String artist() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the album name; if no album name is present in the tag
|
||||||
|
* String::null will be returned.
|
||||||
|
*/
|
||||||
|
virtual String album() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track comment; if no comment is present in the tag
|
||||||
|
* String::null will be returned.
|
||||||
|
*/
|
||||||
|
virtual String comment() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the genre name; if no genre is present in the tag String::null
|
||||||
|
* will be returned.
|
||||||
|
*/
|
||||||
|
virtual String genre() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the year; if there is no year set, this will return 0.
|
||||||
|
*/
|
||||||
|
virtual uint year() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track number; if there is no track number set, this will
|
||||||
|
* return 0.
|
||||||
|
*/
|
||||||
|
virtual uint track() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the title to \a s. If \a s is String::null then this value will be
|
||||||
|
* cleared.
|
||||||
|
*/
|
||||||
|
virtual void setTitle(const String &s) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the artist to \a s. If \a s is String::null then this value will be
|
||||||
|
* cleared.
|
||||||
|
*/
|
||||||
|
virtual void setArtist(const String &s) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the album to \a s. If \a s is String::null then this value will be
|
||||||
|
* cleared.
|
||||||
|
*/
|
||||||
|
virtual void setAlbum(const String &s) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the comment to \a s. If \a s is String::null then this value will be
|
||||||
|
* cleared.
|
||||||
|
*/
|
||||||
|
virtual void setComment(const String &s) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the genre to \a s. If \a s is String::null then this value will be
|
||||||
|
* cleared. For tag formats that use a fixed set of genres, the appropriate
|
||||||
|
* value will be selected based on a string comparison. A list of available
|
||||||
|
* genres for those formats should be available in that type's
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
virtual void setGenre(const String &s) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the year to \a i. If \a s is 0 then this value will be cleared.
|
||||||
|
*/
|
||||||
|
virtual void setYear(uint i) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the track to \a i. If \a s is 0 then this value will be cleared.
|
||||||
|
*/
|
||||||
|
virtual void setTrack(uint i) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the tag does not contain any data. This should be
|
||||||
|
* reimplemented in subclasses that provide more than the basic tagging
|
||||||
|
* abilities in this class.
|
||||||
|
*/
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies the generic data from one tag to another.
|
||||||
|
*
|
||||||
|
* \note This will no affect any of the lower level details of the tag. For
|
||||||
|
* instance if any of the tag type specific data (maybe a URL for a band) is
|
||||||
|
* set, this will not modify or copy that. This just copies using the API
|
||||||
|
* in this class.
|
||||||
|
*
|
||||||
|
* If \a overwrite is true then the values will be unconditionally copied.
|
||||||
|
* If false only empty values will be overwritten.
|
||||||
|
*/
|
||||||
|
static void duplicate(const Tag *source, Tag *target, bool overwrite = true);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
* Construct a Tag. This is protected since tags should only be instantiated
|
||||||
|
* through subclasses.
|
||||||
|
*/
|
||||||
|
Tag();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tag(const Tag &);
|
||||||
|
Tag &operator=(const Tag &);
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
218
Frameworks/TagLib/taglib/taglib/taglib.pro
Normal file
218
Frameworks/TagLib/taglib/taglib/taglib.pro
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
######################################################################
|
||||||
|
# Automatically generated by qmake (2.01a) Fri Feb 1 15:35:13 2008
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
CONFIG += lib_bundle
|
||||||
|
CONFIG += x86 ppc
|
||||||
|
CONFIG -= qt
|
||||||
|
DEFINES += HAVE_ZLIB=1
|
||||||
|
LIBS += -lz
|
||||||
|
TARGET = TagLib
|
||||||
|
VERSION = 1.5
|
||||||
|
DEPENDPATH += . \
|
||||||
|
ape \
|
||||||
|
flac \
|
||||||
|
mpc \
|
||||||
|
mpeg \
|
||||||
|
ogg \
|
||||||
|
ogg/speex \
|
||||||
|
toolkit \
|
||||||
|
trueaudio \
|
||||||
|
wavpack \
|
||||||
|
mpeg/id3v1 \
|
||||||
|
mpeg/id3v2 \
|
||||||
|
ogg/flac \
|
||||||
|
ogg/vorbis \
|
||||||
|
mpeg/id3v2/frames
|
||||||
|
INCLUDEPATH += . \
|
||||||
|
toolkit \
|
||||||
|
mpeg \
|
||||||
|
ogg/vorbis \
|
||||||
|
ogg \
|
||||||
|
flac \
|
||||||
|
ogg/flac \
|
||||||
|
mpc \
|
||||||
|
wavpack \
|
||||||
|
ogg/speex \
|
||||||
|
trueaudio \
|
||||||
|
ape \
|
||||||
|
mpeg/id3v2 \
|
||||||
|
mpeg/id3v1 \
|
||||||
|
mpeg/id3v2/frames
|
||||||
|
|
||||||
|
# Input
|
||||||
|
HEADERS += audioproperties.h \
|
||||||
|
fileref.h \
|
||||||
|
tag.h \
|
||||||
|
taglib_export.h \
|
||||||
|
tagunion.h \
|
||||||
|
ape/apefooter.h \
|
||||||
|
ape/apeitem.h \
|
||||||
|
ape/apetag.h \
|
||||||
|
flac/flacfile.h \
|
||||||
|
flac/flacproperties.h \
|
||||||
|
mpc/mpcfile.h \
|
||||||
|
mpc/mpcproperties.h \
|
||||||
|
mpeg/mpegfile.h \
|
||||||
|
mpeg/mpegheader.h \
|
||||||
|
mpeg/mpegproperties.h \
|
||||||
|
mpeg/xingheader.h \
|
||||||
|
ogg/oggfile.h \
|
||||||
|
ogg/oggpage.h \
|
||||||
|
ogg/oggpageheader.h \
|
||||||
|
ogg/xiphcomment.h \
|
||||||
|
ogg/speex/speexfile.h \
|
||||||
|
ogg/speex/speexproperties.h \
|
||||||
|
toolkit/taglib.h \
|
||||||
|
toolkit/tbytevector.h \
|
||||||
|
toolkit/tbytevectorlist.h \
|
||||||
|
toolkit/tdebug.h \
|
||||||
|
toolkit/tfile.h \
|
||||||
|
toolkit/tlist.h \
|
||||||
|
toolkit/tmap.h \
|
||||||
|
toolkit/tstring.h \
|
||||||
|
toolkit/tstringlist.h \
|
||||||
|
toolkit/unicode.h \
|
||||||
|
trueaudio/trueaudiofile.h \
|
||||||
|
trueaudio/trueaudioproperties.h \
|
||||||
|
wavpack/wavpackfile.h \
|
||||||
|
wavpack/wavpackproperties.h \
|
||||||
|
mpeg/id3v1/id3v1genres.h \
|
||||||
|
mpeg/id3v1/id3v1tag.h \
|
||||||
|
mpeg/id3v2/id3v2extendedheader.h \
|
||||||
|
mpeg/id3v2/id3v2footer.h \
|
||||||
|
mpeg/id3v2/id3v2frame.h \
|
||||||
|
mpeg/id3v2/id3v2framefactory.h \
|
||||||
|
mpeg/id3v2/id3v2header.h \
|
||||||
|
mpeg/id3v2/id3v2synchdata.h \
|
||||||
|
mpeg/id3v2/id3v2tag.h \
|
||||||
|
ogg/flac/oggflacfile.h \
|
||||||
|
ogg/vorbis/vorbisfile.h \
|
||||||
|
ogg/vorbis/vorbisproperties.h \
|
||||||
|
mpeg/id3v2/frames/attachedpictureframe.h \
|
||||||
|
mpeg/id3v2/frames/commentsframe.h \
|
||||||
|
mpeg/id3v2/frames/generalencapsulatedobjectframe.h \
|
||||||
|
mpeg/id3v2/frames/relativevolumeframe.h \
|
||||||
|
mpeg/id3v2/frames/textidentificationframe.h \
|
||||||
|
mpeg/id3v2/frames/uniquefileidentifierframe.h \
|
||||||
|
mpeg/id3v2/frames/unknownframe.h \
|
||||||
|
mpeg/id3v2/frames/unsynchronizedlyricsframe.h \
|
||||||
|
mpeg/id3v2/frames/urllinkframe.h \
|
||||||
|
toolkit/tlist.tcc \
|
||||||
|
toolkit/tmap.tcc
|
||||||
|
SOURCES += audioproperties.cpp \
|
||||||
|
fileref.cpp \
|
||||||
|
tag.cpp \
|
||||||
|
tagunion.cpp \
|
||||||
|
ape/apefooter.cpp \
|
||||||
|
ape/apeitem.cpp \
|
||||||
|
ape/apetag.cpp \
|
||||||
|
flac/flacfile.cpp \
|
||||||
|
flac/flacproperties.cpp \
|
||||||
|
mpc/mpcfile.cpp \
|
||||||
|
mpc/mpcproperties.cpp \
|
||||||
|
mpeg/mpegfile.cpp \
|
||||||
|
mpeg/mpegheader.cpp \
|
||||||
|
mpeg/mpegproperties.cpp \
|
||||||
|
mpeg/xingheader.cpp \
|
||||||
|
ogg/oggfile.cpp \
|
||||||
|
ogg/oggpage.cpp \
|
||||||
|
ogg/oggpageheader.cpp \
|
||||||
|
ogg/xiphcomment.cpp \
|
||||||
|
ogg/speex/speexfile.cpp \
|
||||||
|
ogg/speex/speexproperties.cpp \
|
||||||
|
toolkit/tbytevector.cpp \
|
||||||
|
toolkit/tbytevectorlist.cpp \
|
||||||
|
toolkit/tdebug.cpp \
|
||||||
|
toolkit/tfile.cpp \
|
||||||
|
toolkit/tstring.cpp \
|
||||||
|
toolkit/tstringlist.cpp \
|
||||||
|
toolkit/unicode.cpp \
|
||||||
|
trueaudio/trueaudiofile.cpp \
|
||||||
|
trueaudio/trueaudioproperties.cpp \
|
||||||
|
wavpack/wavpackfile.cpp \
|
||||||
|
wavpack/wavpackproperties.cpp \
|
||||||
|
mpeg/id3v1/id3v1genres.cpp \
|
||||||
|
mpeg/id3v1/id3v1tag.cpp \
|
||||||
|
mpeg/id3v2/id3v2extendedheader.cpp \
|
||||||
|
mpeg/id3v2/id3v2footer.cpp \
|
||||||
|
mpeg/id3v2/id3v2frame.cpp \
|
||||||
|
mpeg/id3v2/id3v2framefactory.cpp \
|
||||||
|
mpeg/id3v2/id3v2header.cpp \
|
||||||
|
mpeg/id3v2/id3v2synchdata.cpp \
|
||||||
|
mpeg/id3v2/id3v2tag.cpp \
|
||||||
|
ogg/flac/oggflacfile.cpp \
|
||||||
|
ogg/vorbis/vorbisfile.cpp \
|
||||||
|
ogg/vorbis/vorbisproperties.cpp \
|
||||||
|
mpeg/id3v2/frames/attachedpictureframe.cpp \
|
||||||
|
mpeg/id3v2/frames/commentsframe.cpp \
|
||||||
|
mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp \
|
||||||
|
mpeg/id3v2/frames/relativevolumeframe.cpp \
|
||||||
|
mpeg/id3v2/frames/textidentificationframe.cpp \
|
||||||
|
mpeg/id3v2/frames/uniquefileidentifierframe.cpp \
|
||||||
|
mpeg/id3v2/frames/unknownframe.cpp \
|
||||||
|
mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp \
|
||||||
|
mpeg/id3v2/frames/urllinkframe.cpp
|
||||||
|
|
||||||
|
FRAMEWORK_HEADERS.version = Versions
|
||||||
|
FRAMEWORK_HEADERS.files = \
|
||||||
|
audioproperties.h \
|
||||||
|
fileref.h \
|
||||||
|
tag.h \
|
||||||
|
taglib_export.h \
|
||||||
|
ape/apefooter.h \
|
||||||
|
ape/apeitem.h \
|
||||||
|
ape/apetag.h \
|
||||||
|
flac/flacfile.h \
|
||||||
|
flac/flacproperties.h \
|
||||||
|
mpc/mpcfile.h \
|
||||||
|
mpc/mpcproperties.h \
|
||||||
|
mpeg/mpegfile.h \
|
||||||
|
mpeg/mpegheader.h \
|
||||||
|
mpeg/mpegproperties.h \
|
||||||
|
mpeg/xingheader.h \
|
||||||
|
ogg/oggfile.h \
|
||||||
|
ogg/oggpage.h \
|
||||||
|
ogg/oggpageheader.h \
|
||||||
|
ogg/xiphcomment.h \
|
||||||
|
ogg/speex/speexfile.h \
|
||||||
|
ogg/speex/speexproperties.h \
|
||||||
|
toolkit/taglib.h \
|
||||||
|
toolkit/tbytevector.h \
|
||||||
|
toolkit/tbytevectorlist.h \
|
||||||
|
toolkit/tfile.h \
|
||||||
|
toolkit/tlist.h \
|
||||||
|
toolkit/tmap.h \
|
||||||
|
toolkit/tstring.h \
|
||||||
|
toolkit/tstringlist.h \
|
||||||
|
toolkit/unicode.h \
|
||||||
|
trueaudio/trueaudiofile.h \
|
||||||
|
trueaudio/trueaudioproperties.h \
|
||||||
|
wavpack/wavpackfile.h \
|
||||||
|
wavpack/wavpackproperties.h \
|
||||||
|
mpeg/id3v1/id3v1genres.h \
|
||||||
|
mpeg/id3v1/id3v1tag.h \
|
||||||
|
mpeg/id3v2/id3v2extendedheader.h \
|
||||||
|
mpeg/id3v2/id3v2footer.h \
|
||||||
|
mpeg/id3v2/id3v2frame.h \
|
||||||
|
mpeg/id3v2/id3v2framefactory.h \
|
||||||
|
mpeg/id3v2/id3v2header.h \
|
||||||
|
mpeg/id3v2/id3v2synchdata.h \
|
||||||
|
mpeg/id3v2/id3v2tag.h \
|
||||||
|
ogg/flac/oggflacfile.h \
|
||||||
|
ogg/vorbis/vorbisfile.h \
|
||||||
|
ogg/vorbis/vorbisproperties.h \
|
||||||
|
mpeg/id3v2/frames/attachedpictureframe.h \
|
||||||
|
mpeg/id3v2/frames/commentsframe.h \
|
||||||
|
mpeg/id3v2/frames/generalencapsulatedobjectframe.h \
|
||||||
|
mpeg/id3v2/frames/relativevolumeframe.h \
|
||||||
|
mpeg/id3v2/frames/textidentificationframe.h \
|
||||||
|
mpeg/id3v2/frames/uniquefileidentifierframe.h \
|
||||||
|
mpeg/id3v2/frames/unknownframe.h \
|
||||||
|
mpeg/id3v2/frames/unsynchronizedlyricsframe.h \
|
||||||
|
mpeg/id3v2/frames/urllinkframe.h \
|
||||||
|
toolkit/tlist.tcc \
|
||||||
|
toolkit/tmap.tcc
|
||||||
|
FRAMEWORK_HEADERS.path = Headers
|
||||||
|
QMAKE_BUNDLE_DATA += FRAMEWORK_HEADERS
|
39
Frameworks/TagLib/taglib/taglib/taglib_export.h
Normal file
39
Frameworks/TagLib/taglib/taglib/taglib_export.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_EXPORT_H
|
||||||
|
#define TAGLIB_EXPORT_H
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#ifdef MAKE_TAGLIB_LIB
|
||||||
|
#define TAGLIB_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define TAGLIB_EXPORT __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define TAGLIB_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
185
Frameworks/TagLib/taglib/taglib/tagunion.cpp
Normal file
185
Frameworks/TagLib/taglib/taglib/tagunion.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file 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"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
#define stringUnion(method) \
|
||||||
|
if(tag(0) && !tag(0)->method().isEmpty()) \
|
||||||
|
return tag(0)->method(); \
|
||||||
|
if(tag(1) && !tag(1)->method().isEmpty()) \
|
||||||
|
return tag(1)->method(); \
|
||||||
|
if(tag(2) && !tag(2)->method().isEmpty()) \
|
||||||
|
return tag(2)->method(); \
|
||||||
|
return String::null \
|
||||||
|
|
||||||
|
#define numberUnion(method) \
|
||||||
|
if(tag(0) && tag(0)->method() > 0) \
|
||||||
|
return tag(0)->method(); \
|
||||||
|
if(tag(1) && tag(1)->method() > 0) \
|
||||||
|
return tag(1)->method(); \
|
||||||
|
if(tag(2) && tag(2)->method() > 0) \
|
||||||
|
return tag(2)->method(); \
|
||||||
|
return 0
|
||||||
|
|
||||||
|
#define setUnion(method, value) \
|
||||||
|
if(tag(0)) \
|
||||||
|
tag(0)->set##method(value); \
|
||||||
|
if(tag(1)) \
|
||||||
|
tag(1)->set##method(value); \
|
||||||
|
if(tag(2)) \
|
||||||
|
tag(2)->set##method(value); \
|
||||||
|
|
||||||
|
class TagUnion::TagUnionPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TagUnionPrivate() : tags(3, static_cast<Tag *>(0))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
~TagUnionPrivate()
|
||||||
|
{
|
||||||
|
delete tags[0];
|
||||||
|
delete tags[1];
|
||||||
|
delete tags[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Tag *> tags;
|
||||||
|
};
|
||||||
|
|
||||||
|
TagUnion::TagUnion(Tag *first, Tag *second, Tag *third)
|
||||||
|
{
|
||||||
|
d = new TagUnionPrivate;
|
||||||
|
|
||||||
|
d->tags[0] = first;
|
||||||
|
d->tags[1] = second;
|
||||||
|
d->tags[2] = third;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagUnion::~TagUnion()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag *TagUnion::operator[](int index) const
|
||||||
|
{
|
||||||
|
return tag(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag *TagUnion::tag(int index) const
|
||||||
|
{
|
||||||
|
return d->tags[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::set(int index, Tag *tag)
|
||||||
|
{
|
||||||
|
delete d->tags[index];
|
||||||
|
d->tags[index] = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
String TagUnion::title() const
|
||||||
|
{
|
||||||
|
stringUnion(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
String TagUnion::artist() const
|
||||||
|
{
|
||||||
|
stringUnion(artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
String TagUnion::album() const
|
||||||
|
{
|
||||||
|
stringUnion(album);
|
||||||
|
}
|
||||||
|
|
||||||
|
String TagUnion::comment() const
|
||||||
|
{
|
||||||
|
stringUnion(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
String TagUnion::genre() const
|
||||||
|
{
|
||||||
|
stringUnion(genre);
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint TagUnion::year() const
|
||||||
|
{
|
||||||
|
numberUnion(year);
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint TagUnion::track() const
|
||||||
|
{
|
||||||
|
numberUnion(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::setTitle(const String &s)
|
||||||
|
{
|
||||||
|
setUnion(Title, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::setArtist(const String &s)
|
||||||
|
{
|
||||||
|
setUnion(Artist, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::setAlbum(const String &s)
|
||||||
|
{
|
||||||
|
setUnion(Album, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::setComment(const String &s)
|
||||||
|
{
|
||||||
|
setUnion(Comment, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::setGenre(const String &s)
|
||||||
|
{
|
||||||
|
setUnion(Genre, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::setYear(uint i)
|
||||||
|
{
|
||||||
|
setUnion(Year, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagUnion::setTrack(uint i)
|
||||||
|
{
|
||||||
|
setUnion(Track, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagUnion::isEmpty() const
|
||||||
|
{
|
||||||
|
if(d->tags[0] && !d->tags[0]->isEmpty())
|
||||||
|
return false;
|
||||||
|
if(d->tags[1] && !d->tags[1]->isEmpty())
|
||||||
|
return false;
|
||||||
|
if(d->tags[2] && !d->tags[2]->isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
95
Frameworks/TagLib/taglib/taglib/tagunion.h
Normal file
95
Frameworks/TagLib/taglib/taglib/tagunion.h
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_TAGUNION_H
|
||||||
|
#define TAGLIB_TAGUNION_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TagUnion : public Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum AccessType { Read, Write };
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates a TagLib::Tag that is the union of \a first, \a second, and
|
||||||
|
* \a third. The TagUnion takes ownership of these tags and will handle
|
||||||
|
* their deletion.
|
||||||
|
*/
|
||||||
|
TagUnion(Tag *first = 0, Tag *second = 0, Tag *third = 0);
|
||||||
|
|
||||||
|
virtual ~TagUnion();
|
||||||
|
|
||||||
|
Tag *operator[](int index) const;
|
||||||
|
Tag *tag(int index) const;
|
||||||
|
|
||||||
|
void set(int index, Tag *tag);
|
||||||
|
|
||||||
|
virtual String title() const;
|
||||||
|
virtual String artist() const;
|
||||||
|
virtual String album() const;
|
||||||
|
virtual String comment() const;
|
||||||
|
virtual String genre() const;
|
||||||
|
virtual uint year() const;
|
||||||
|
virtual uint track() const;
|
||||||
|
|
||||||
|
virtual void setTitle(const String &s);
|
||||||
|
virtual void setArtist(const String &s);
|
||||||
|
virtual void setAlbum(const String &s);
|
||||||
|
virtual void setComment(const String &s);
|
||||||
|
virtual void setGenre(const String &s);
|
||||||
|
virtual void setYear(uint i);
|
||||||
|
virtual void setTrack(uint i);
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
|
template <class T> T *access(int index, bool create)
|
||||||
|
{
|
||||||
|
if(!create || tag(index))
|
||||||
|
return static_cast<T *>(tag(index));
|
||||||
|
|
||||||
|
set(index, new T);
|
||||||
|
return static_cast<T *>(tag(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TagUnion(const Tag &);
|
||||||
|
TagUnion &operator=(const Tag &);
|
||||||
|
|
||||||
|
class TagUnionPrivate;
|
||||||
|
TagUnionPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
177
Frameworks/TagLib/taglib/taglib/toolkit/taglib.h
Normal file
177
Frameworks/TagLib/taglib/taglib/toolkit/taglib.h
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_H
|
||||||
|
#define TAGLIB_H
|
||||||
|
|
||||||
|
#define TAGLIB_MAJOR_VERSION 1
|
||||||
|
#define TAGLIB_MINOR_VERSION 5
|
||||||
|
#define TAGLIB_PATCH_VERSION 0
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//! A namespace for all TagLib related classes and functions
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This namespace contains everything in TagLib. For projects working with
|
||||||
|
* TagLib extensively it may be conveniten to add a
|
||||||
|
* \code
|
||||||
|
* using namespace TagLib;
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
class String;
|
||||||
|
|
||||||
|
typedef wchar_t wchar;
|
||||||
|
typedef unsigned char uchar;
|
||||||
|
typedef unsigned int uint;
|
||||||
|
typedef unsigned long ulong;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3)
|
||||||
|
* so I'm providing something here that should be constant.
|
||||||
|
*/
|
||||||
|
typedef std::basic_string<wchar> wstring;
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class.
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
* This is just used as a base class for shared classes in TagLib.
|
||||||
|
*
|
||||||
|
* \warning This <b>is not</b> part of the TagLib public API!
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RefCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RefCounter() : refCount(1) {}
|
||||||
|
void ref() { refCount++; }
|
||||||
|
bool deref() { return ! --refCount ; }
|
||||||
|
int count() { return refCount; }
|
||||||
|
private:
|
||||||
|
uint refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DO_NOT_DOCUMENT
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \mainpage TagLib
|
||||||
|
*
|
||||||
|
* \section intro Introduction
|
||||||
|
*
|
||||||
|
* TagLib is a library for reading and editing audio meta data, commonly know as \e tags.
|
||||||
|
*
|
||||||
|
* Features:
|
||||||
|
* - A clean, high level, C++ API to handling audio meta data.
|
||||||
|
* - Format specific APIs for advanced API users.
|
||||||
|
* - ID3v1, ID3v2, APE, FLAC and Xiph tag formats.
|
||||||
|
* - MP3, MPC, FLAC, Ogg FLAC, Ogg Vorbis and Speex file formats.
|
||||||
|
* - Basic audio file properties such as length, sample rate, etc.
|
||||||
|
* - Long term binary and source compatibility.
|
||||||
|
* - Extensible design, notably the ability to add other formats or extend current formats as a library user.
|
||||||
|
* - Full support for unicode and internationalized tags.
|
||||||
|
* - Dual <a href="http://www.mozilla.org/MPL/MPL-1.1.html">MPL</a> and
|
||||||
|
* <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">LGPL</a> licenses.
|
||||||
|
* - No external toolkit dependancies.
|
||||||
|
*
|
||||||
|
* \section why Why TagLib?
|
||||||
|
*
|
||||||
|
* TagLib originally was written to provide an updated and improved ID3v2 implementation in C++ for use
|
||||||
|
* in a variety of Open Source projects. Since development began in 2002 and the 1.0 release in 2004
|
||||||
|
* it has expanded to cover a wide variety of tag and file formats and is used in a wide variety of
|
||||||
|
* Open Source and proprietary applications. It now supports a variety of UNIXes, including Apple's OS
|
||||||
|
* X, as well as Microsoft Windows.
|
||||||
|
*
|
||||||
|
* \section commercial Usage in Commercial Applications
|
||||||
|
*
|
||||||
|
* TagLib's licenses \e do allow usage within propriety (\e closed) applications, however TagLib is \e not
|
||||||
|
* public domain. Please note the requirements of the LGPL or MPL, and adhere to at least one of them.
|
||||||
|
* In simple terms, you must at a minimum note your usage of TagLib, note the licensing terms of TagLib and
|
||||||
|
* if you make changes to TagLib publish them. Please review the licenses above before using TagLib in your
|
||||||
|
* software. Note that you may choose either the MPL or the LGPL, you do not have to fulfill the
|
||||||
|
* requirements of both.
|
||||||
|
*
|
||||||
|
* \section installing Installing TagLib
|
||||||
|
*
|
||||||
|
* Please see the <a href="http://developer.kde.org/~wheeler/taglib.html">TagLib website</a> for the latest
|
||||||
|
* downloads.
|
||||||
|
*
|
||||||
|
* Instructions for installing TagLib vary per platform, but generally speaking on UNIX standard configure and
|
||||||
|
* make commands are provided. TagLib installs a taglib-config and package-config file to make it easier to
|
||||||
|
* integrate into various build systems. Note that TagLib's include install directory \e must be included in
|
||||||
|
* the header include path. Simply adding <taglib/tag.h> will \e not work.
|
||||||
|
*
|
||||||
|
* On Windows, TagLib can be built using the CMake build systems.
|
||||||
|
*
|
||||||
|
* \section start Getting Started
|
||||||
|
*
|
||||||
|
* TagLib provides both simple, abstract APIs which make it possible to ignore the differences between tagging
|
||||||
|
* formats and format specific APIs which allow programmers to work with the features of specific tagging
|
||||||
|
* schemes. There is a similar abstraction mechanism for AudioProperties.
|
||||||
|
*
|
||||||
|
* The best place to start is with the <b>Class Hierarchy</b> linked at the top of the page. The File and
|
||||||
|
* AudioProperties classes and their subclasses are the core of TagLib. The FileRef class is also a convenient
|
||||||
|
* way for using a value-based handle.
|
||||||
|
*
|
||||||
|
* \note When working with FileRef please consider that it has only the most basic (extension-based) file
|
||||||
|
* type resolution. Please see its documentation on how to plug in more advanced file type resolution. (Such
|
||||||
|
* resolution may be part of later TagLib releases by default.)
|
||||||
|
*
|
||||||
|
* Here's a very simple example with TagLib:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
*
|
||||||
|
* TagLib::FileRef f("Latex Solar Beef.mp3");
|
||||||
|
* TagLib::String artist = f.tag()->artist(); // artist == "Frank Zappa"
|
||||||
|
*
|
||||||
|
* f.tag()->setAlbum("Fillmore East");
|
||||||
|
* f.save();
|
||||||
|
*
|
||||||
|
* TagLib::FileRef g("Free City Rhymes.ogg");
|
||||||
|
* TagLib::String album = g.tag()->album(); // album == "NYC Ghosts & Flowers"
|
||||||
|
*
|
||||||
|
* g.tag()->setTrack(1);
|
||||||
|
* g.save();
|
||||||
|
*
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* More examples can be found in the \e examples directory of the source distribution.
|
||||||
|
*
|
||||||
|
* \section Contact
|
||||||
|
*
|
||||||
|
* Questions about TagLib should be directed to the TagLib mailing list, not directly to the author.
|
||||||
|
*
|
||||||
|
* - <a href="http://developer.kde.org/~wheeler/taglib/">TagLib Homepage</a>
|
||||||
|
* - <a href="https://mail.kde.org/mailman/listinfo/taglib-devel">TagLib Mailing List (taglib-devel@kde.org)</a>
|
||||||
|
*
|
||||||
|
* \author Scott Wheeler <wheeler@kde.org> et al.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
677
Frameworks/TagLib/taglib/taglib/toolkit/tbytevector.cpp
Normal file
677
Frameworks/TagLib/taglib/taglib/toolkit/tbytevector.cpp
Normal file
|
@ -0,0 +1,677 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tbytevector.h"
|
||||||
|
|
||||||
|
// This is a bit ugly to keep writing over and over again.
|
||||||
|
|
||||||
|
// A rather obscure feature of the C++ spec that I hadn't thought of that makes
|
||||||
|
// working with C libs much more effecient. There's more here:
|
||||||
|
//
|
||||||
|
// http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp
|
||||||
|
|
||||||
|
#define DATA(x) (&(x->data[0]))
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
static const uint crcTable[256] = {
|
||||||
|
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
|
||||||
|
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||||
|
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
|
||||||
|
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||||
|
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
|
||||||
|
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||||
|
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
|
||||||
|
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||||
|
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
|
||||||
|
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||||
|
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
|
||||||
|
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||||
|
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
|
||||||
|
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||||
|
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
|
||||||
|
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||||
|
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
|
||||||
|
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||||
|
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
|
||||||
|
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||||
|
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
|
||||||
|
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||||
|
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
|
||||||
|
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||||
|
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
|
||||||
|
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||||
|
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
|
||||||
|
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||||
|
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
|
||||||
|
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||||
|
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
|
||||||
|
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||||
|
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
|
||||||
|
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||||
|
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
|
||||||
|
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||||
|
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
|
||||||
|
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||||
|
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
|
||||||
|
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||||
|
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
|
||||||
|
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||||
|
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* A templatized KMP find that works both with a ByteVector and a ByteVectorMirror.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class Vector>
|
||||||
|
int vectorFind(const Vector &v, const Vector &pattern, uint offset, int byteAlign)
|
||||||
|
{
|
||||||
|
if(pattern.size() > v.size() || offset > v.size() - 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// Let's go ahead and special case a pattern of size one since that's common
|
||||||
|
// and easy to make fast.
|
||||||
|
|
||||||
|
if(pattern.size() == 1) {
|
||||||
|
char p = pattern[0];
|
||||||
|
for(uint i = offset; i < v.size(); i++) {
|
||||||
|
if(v[i] == p && (i - offset) % byteAlign == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar lastOccurrence[256];
|
||||||
|
|
||||||
|
for(uint i = 0; i < 256; ++i)
|
||||||
|
lastOccurrence[i] = uchar(pattern.size());
|
||||||
|
|
||||||
|
for(uint i = 0; i < pattern.size() - 1; ++i)
|
||||||
|
lastOccurrence[uchar(pattern[i])] = uchar(pattern.size() - i - 1);
|
||||||
|
|
||||||
|
for(uint i = pattern.size() - 1 + offset; i < v.size(); i += lastOccurrence[uchar(v.at(i))]) {
|
||||||
|
int iBuffer = i;
|
||||||
|
int iPattern = pattern.size() - 1;
|
||||||
|
|
||||||
|
while(iPattern >= 0 && v.at(iBuffer) == pattern[iPattern]) {
|
||||||
|
--iBuffer;
|
||||||
|
--iPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-1 == iPattern && (iBuffer + 1 - offset) % byteAlign == 0)
|
||||||
|
return iBuffer + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Wraps the accessors to a ByteVector to make the search algorithm access the
|
||||||
|
* elements in reverse.
|
||||||
|
*
|
||||||
|
* \see vectorFind()
|
||||||
|
* \see ByteVector::rfind()
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ByteVectorMirror
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVectorMirror(const ByteVector &source) : v(source) {}
|
||||||
|
|
||||||
|
const char operator[](int index) const
|
||||||
|
{
|
||||||
|
return v[v.size() - index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char at(int index) const
|
||||||
|
{
|
||||||
|
return v.at(v.size() - index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVectorMirror mid(uint index, uint length = 0xffffffff) const
|
||||||
|
{
|
||||||
|
return length == 0xffffffff ? v.mid(0, index) : v.mid(index - length, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint size() const
|
||||||
|
{
|
||||||
|
return v.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int find(const ByteVectorMirror &pattern, uint offset = 0, int byteAlign = 1) const
|
||||||
|
{
|
||||||
|
ByteVectorMirror v(*this);
|
||||||
|
|
||||||
|
if(offset > 0) {
|
||||||
|
offset = size() - offset - pattern.size();
|
||||||
|
if(offset >= size())
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int pos = vectorFind<ByteVectorMirror>(v, pattern, offset, byteAlign);
|
||||||
|
|
||||||
|
// If the offset is zero then we need to adjust the location in the search
|
||||||
|
// to be appropriately reversed. If not we need to account for the fact
|
||||||
|
// that the recursive call (called from the above line) has already ajusted
|
||||||
|
// for this but that the normal templatized find above will add the offset
|
||||||
|
// to the returned value.
|
||||||
|
//
|
||||||
|
// This is a little confusing at first if you don't first stop to think
|
||||||
|
// through the logic involved in the forward search.
|
||||||
|
|
||||||
|
if(pos == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return size() - pos - pattern.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ByteVector &v;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T toNumber(const std::vector<char> &data, bool mostSignificantByteFirst)
|
||||||
|
{
|
||||||
|
T sum = 0;
|
||||||
|
|
||||||
|
if(data.size() <= 0) {
|
||||||
|
debug("ByteVectorMirror::toNumber<T>() -- data is empty, returning 0");
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint size = sizeof(T);
|
||||||
|
uint last = data.size() > size ? size - 1 : data.size() - 1;
|
||||||
|
|
||||||
|
for(uint i = 0; i <= last; i++)
|
||||||
|
sum |= (T) uchar(data[i]) << ((mostSignificantByteFirst ? last - i : i) * 8);
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
ByteVector fromNumber(T value, bool mostSignificantByteFirst)
|
||||||
|
{
|
||||||
|
int size = sizeof(T);
|
||||||
|
|
||||||
|
ByteVector v(size, 0);
|
||||||
|
|
||||||
|
for(int i = 0; i < size; i++)
|
||||||
|
v[i] = uchar(value >> ((mostSignificantByteFirst ? size - 1 - i : i) * 8) & 0xff);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class ByteVector::ByteVectorPrivate : public RefCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVectorPrivate() : RefCounter(), size(0) {}
|
||||||
|
ByteVectorPrivate(const std::vector<char> &v) : RefCounter(), data(v), size(v.size()) {}
|
||||||
|
ByteVectorPrivate(TagLib::uint len, char value) : RefCounter(), data(len, value), size(len) {}
|
||||||
|
|
||||||
|
std::vector<char> data;
|
||||||
|
|
||||||
|
// std::vector<T>::size() is very slow, so we'll cache the value
|
||||||
|
|
||||||
|
uint size;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ByteVector ByteVector::null;
|
||||||
|
|
||||||
|
ByteVector ByteVector::fromCString(const char *s, uint length)
|
||||||
|
{
|
||||||
|
ByteVector v;
|
||||||
|
|
||||||
|
if(length == 0xffffffff)
|
||||||
|
v.setData(s);
|
||||||
|
else
|
||||||
|
v.setData(s, length);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst)
|
||||||
|
{
|
||||||
|
return fromNumber<uint>(value, mostSignificantByteFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst)
|
||||||
|
{
|
||||||
|
return fromNumber<short>(value, mostSignificantByteFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst)
|
||||||
|
{
|
||||||
|
return fromNumber<long long>(value, mostSignificantByteFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ByteVector::ByteVector()
|
||||||
|
{
|
||||||
|
d = new ByteVectorPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::ByteVector(uint size, char value)
|
||||||
|
{
|
||||||
|
d = new ByteVectorPrivate(size, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::ByteVector(const ByteVector &v) : d(v.d)
|
||||||
|
{
|
||||||
|
d->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::ByteVector(char c)
|
||||||
|
{
|
||||||
|
d = new ByteVectorPrivate;
|
||||||
|
d->data.push_back(c);
|
||||||
|
d->size = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::ByteVector(const char *data, uint length)
|
||||||
|
{
|
||||||
|
d = new ByteVectorPrivate;
|
||||||
|
setData(data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::ByteVector(const char *data)
|
||||||
|
{
|
||||||
|
d = new ByteVectorPrivate;
|
||||||
|
setData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::~ByteVector()
|
||||||
|
{
|
||||||
|
if(d->deref())
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::setData(const char *data, uint length)
|
||||||
|
{
|
||||||
|
detach();
|
||||||
|
|
||||||
|
resize(length);
|
||||||
|
|
||||||
|
if(length > 0)
|
||||||
|
::memcpy(DATA(d), data, length);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::setData(const char *data)
|
||||||
|
{
|
||||||
|
return setData(data, ::strlen(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ByteVector::data()
|
||||||
|
{
|
||||||
|
detach();
|
||||||
|
return size() > 0 ? DATA(d) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ByteVector::data() const
|
||||||
|
{
|
||||||
|
return size() > 0 ? DATA(d) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ByteVector::mid(uint index, uint length) const
|
||||||
|
{
|
||||||
|
ByteVector v;
|
||||||
|
|
||||||
|
if(index > size())
|
||||||
|
return v;
|
||||||
|
|
||||||
|
ConstIterator endIt;
|
||||||
|
|
||||||
|
if(length < 0xffffffff && length + index < size())
|
||||||
|
endIt = d->data.begin() + index + length;
|
||||||
|
else
|
||||||
|
endIt = d->data.end();
|
||||||
|
|
||||||
|
v.d->data.insert(v.d->data.begin(), ConstIterator(d->data.begin() + index), endIt);
|
||||||
|
v.d->size = v.d->data.size();
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ByteVector::at(uint index) const
|
||||||
|
{
|
||||||
|
return index < size() ? d->data[index] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ByteVector::find(const ByteVector &pattern, uint offset, int byteAlign) const
|
||||||
|
{
|
||||||
|
return vectorFind<ByteVector>(*this, pattern, offset, byteAlign);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ByteVector::rfind(const ByteVector &pattern, uint offset, int byteAlign) const
|
||||||
|
{
|
||||||
|
// Ok, this is a little goofy, but pretty cool after it sinks in. Instead of
|
||||||
|
// reversing the find method's Boyer-Moore search algorithm I created a "mirror"
|
||||||
|
// for a ByteVector to reverse the behavior of the accessors.
|
||||||
|
|
||||||
|
ByteVectorMirror v(*this);
|
||||||
|
ByteVectorMirror p(pattern);
|
||||||
|
|
||||||
|
return v.find(p, offset, byteAlign);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::containsAt(const ByteVector &pattern, uint offset, uint patternOffset, uint patternLength) const
|
||||||
|
{
|
||||||
|
if(pattern.size() < patternLength)
|
||||||
|
patternLength = pattern.size();
|
||||||
|
|
||||||
|
// do some sanity checking -- all of these things are needed for the search to be valid
|
||||||
|
|
||||||
|
if(patternLength > size() || offset >= size() || patternOffset >= pattern.size() || patternLength == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// loop through looking for a mismatch
|
||||||
|
|
||||||
|
for(uint i = 0; i < patternLength - patternOffset; i++) {
|
||||||
|
if(at(i + offset) != pattern[i + patternOffset])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::startsWith(const ByteVector &pattern) const
|
||||||
|
{
|
||||||
|
return containsAt(pattern, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::endsWith(const ByteVector &pattern) const
|
||||||
|
{
|
||||||
|
return containsAt(pattern, size() - pattern.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &with)
|
||||||
|
{
|
||||||
|
if(pattern.size() == 0 || pattern.size() > size())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
const int patternSize = pattern.size();
|
||||||
|
const int withSize = with.size();
|
||||||
|
|
||||||
|
int offset = find(pattern);
|
||||||
|
|
||||||
|
while(offset >= 0) {
|
||||||
|
|
||||||
|
const int originalSize = size();
|
||||||
|
|
||||||
|
if(withSize > patternSize)
|
||||||
|
resize(originalSize + withSize - patternSize);
|
||||||
|
|
||||||
|
if(patternSize != withSize)
|
||||||
|
::memcpy(data() + offset + withSize, mid(offset + patternSize).data(), originalSize - offset - patternSize);
|
||||||
|
|
||||||
|
if(withSize < patternSize)
|
||||||
|
resize(originalSize + withSize - patternSize);
|
||||||
|
|
||||||
|
::memcpy(data() + offset, with.data(), withSize);
|
||||||
|
|
||||||
|
offset = find(pattern, offset + withSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ByteVector::endsWithPartialMatch(const ByteVector &pattern) const
|
||||||
|
{
|
||||||
|
if(pattern.size() > size())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const int startIndex = size() - pattern.size();
|
||||||
|
|
||||||
|
// try to match the last n-1 bytes from the vector (where n is the pattern
|
||||||
|
// size) -- continue trying to match n-2, n-3...1 bytes
|
||||||
|
|
||||||
|
for(uint i = 1; i < pattern.size(); i++) {
|
||||||
|
if(containsAt(pattern, startIndex + i, 0, pattern.size() - i))
|
||||||
|
return startIndex + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::append(const ByteVector &v)
|
||||||
|
{
|
||||||
|
if(v.d->size == 0)
|
||||||
|
return *this; // Simply return if appending nothing.
|
||||||
|
|
||||||
|
detach();
|
||||||
|
|
||||||
|
uint originalSize = d->size;
|
||||||
|
resize(d->size + v.d->size);
|
||||||
|
::memcpy(DATA(d) + originalSize, DATA(v.d), v.size());
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::clear()
|
||||||
|
{
|
||||||
|
detach();
|
||||||
|
d->data.clear();
|
||||||
|
d->size = 0;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint ByteVector::size() const
|
||||||
|
{
|
||||||
|
return d->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::resize(uint size, char padding)
|
||||||
|
{
|
||||||
|
if(d->size < size) {
|
||||||
|
d->data.reserve(size);
|
||||||
|
d->data.insert(d->data.end(), size - d->size, padding);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d->data.erase(d->data.begin() + size, d->data.end());
|
||||||
|
|
||||||
|
d->size = size;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::Iterator ByteVector::begin()
|
||||||
|
{
|
||||||
|
return d->data.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::ConstIterator ByteVector::begin() const
|
||||||
|
{
|
||||||
|
return d->data.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::Iterator ByteVector::end()
|
||||||
|
{
|
||||||
|
return d->data.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector::ConstIterator ByteVector::end() const
|
||||||
|
{
|
||||||
|
return d->data.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::isNull() const
|
||||||
|
{
|
||||||
|
return d == null.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::isEmpty() const
|
||||||
|
{
|
||||||
|
return d->data.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint ByteVector::checksum() const
|
||||||
|
{
|
||||||
|
uint sum = 0;
|
||||||
|
for(ByteVector::ConstIterator it = begin(); it != end(); ++it)
|
||||||
|
sum = (sum << 8) ^ crcTable[((sum >> 24) & 0xff) ^ uchar(*it)];
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const
|
||||||
|
{
|
||||||
|
return toNumber<uint>(d->data, mostSignificantByteFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
short ByteVector::toShort(bool mostSignificantByteFirst) const
|
||||||
|
{
|
||||||
|
return toNumber<unsigned short>(d->data, mostSignificantByteFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
long long ByteVector::toLongLong(bool mostSignificantByteFirst) const
|
||||||
|
{
|
||||||
|
return toNumber<unsigned long long>(d->data, mostSignificantByteFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char &ByteVector::operator[](int index) const
|
||||||
|
{
|
||||||
|
return d->data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
char &ByteVector::operator[](int index)
|
||||||
|
{
|
||||||
|
detach();
|
||||||
|
|
||||||
|
return d->data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::operator==(const ByteVector &v) const
|
||||||
|
{
|
||||||
|
if(d->size != v.d->size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ::memcmp(data(), v.data(), size()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::operator!=(const ByteVector &v) const
|
||||||
|
{
|
||||||
|
return !operator==(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::operator==(const char *s) const
|
||||||
|
{
|
||||||
|
if(d->size != ::strlen(s))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ::memcmp(data(), s, d->size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::operator!=(const char *s) const
|
||||||
|
{
|
||||||
|
return !operator==(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::operator<(const ByteVector &v) const
|
||||||
|
{
|
||||||
|
int result = ::memcmp(data(), v.data(), d->size < v.d->size ? d->size : v.d->size);
|
||||||
|
|
||||||
|
if(result != 0)
|
||||||
|
return result < 0;
|
||||||
|
else
|
||||||
|
return size() < v.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ByteVector::operator>(const ByteVector &v) const
|
||||||
|
{
|
||||||
|
return v < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ByteVector::operator+(const ByteVector &v) const
|
||||||
|
{
|
||||||
|
ByteVector sum(*this);
|
||||||
|
sum.append(v);
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::operator=(const ByteVector &v)
|
||||||
|
{
|
||||||
|
if(&v == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
if(d->deref())
|
||||||
|
delete d;
|
||||||
|
|
||||||
|
d = v.d;
|
||||||
|
d->ref();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::operator=(char c)
|
||||||
|
{
|
||||||
|
*this = ByteVector(c);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector &ByteVector::operator=(const char *data)
|
||||||
|
{
|
||||||
|
*this = ByteVector(data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void ByteVector::detach()
|
||||||
|
{
|
||||||
|
if(d->count() > 1) {
|
||||||
|
d->deref();
|
||||||
|
d = new ByteVectorPrivate(d->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// related functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &s, const ByteVector &v)
|
||||||
|
{
|
||||||
|
for(TagLib::uint i = 0; i < v.size(); i++)
|
||||||
|
s << v[i];
|
||||||
|
return s;
|
||||||
|
}
|
409
Frameworks/TagLib/taglib/taglib/toolkit/tbytevector.h
Normal file
409
Frameworks/TagLib/taglib/taglib/toolkit/tbytevector.h
Normal file
|
@ -0,0 +1,409 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_BYTEVECTOR_H
|
||||||
|
#define TAGLIB_BYTEVECTOR_H
|
||||||
|
|
||||||
|
#include "taglib.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
//! A byte vector
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This class provides a byte vector with some methods that are useful for
|
||||||
|
* tagging purposes. Many of the search functions are tailored to what is
|
||||||
|
* useful for finding tag related paterns in a data array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT ByteVector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
typedef std::vector<char>::iterator Iterator;
|
||||||
|
typedef std::vector<char>::const_iterator ConstIterator;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an empty byte vector.
|
||||||
|
*/
|
||||||
|
ByteVector();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Construct a vector of size \a size with all values set to \a value by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
ByteVector(uint size, char value = 0);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Contructs a byte vector that is a copy of \a v.
|
||||||
|
*/
|
||||||
|
ByteVector(const ByteVector &v);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Contructs a byte vector that contains \a c.
|
||||||
|
*/
|
||||||
|
ByteVector(char c);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a byte vector that copies \a data for up to \a length bytes.
|
||||||
|
*/
|
||||||
|
ByteVector(const char *data, uint length);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a byte vector that copies \a data up to the first null
|
||||||
|
* byte. The behavior is undefined if \a data is not null terminated.
|
||||||
|
* This is particularly useful for constructing byte arrays from string
|
||||||
|
* constants.
|
||||||
|
*/
|
||||||
|
ByteVector(const char *data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this ByteVector instance.
|
||||||
|
*/
|
||||||
|
virtual ~ByteVector();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the data for the byte array using the first \a length bytes of \a data
|
||||||
|
*/
|
||||||
|
ByteVector &setData(const char *data, uint length);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the data for the byte array copies \a data up to the first null
|
||||||
|
* byte. The behavior is undefined if \a data is not null terminated.
|
||||||
|
*/
|
||||||
|
ByteVector &setData(const char *data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the internal data structure.
|
||||||
|
*
|
||||||
|
* \warning Care should be taken when modifying this data structure as it is
|
||||||
|
* easy to corrupt the ByteVector when doing so. Specifically, while the
|
||||||
|
* data may be changed, its length may not be.
|
||||||
|
*/
|
||||||
|
char *data();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the internal data structure which may not be modified.
|
||||||
|
*/
|
||||||
|
const char *data() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a byte vector made up of the bytes starting at \a index and
|
||||||
|
* for \a length bytes. If \a length is not specified it will return the bytes
|
||||||
|
* from \a index to the end of the vector.
|
||||||
|
*/
|
||||||
|
ByteVector mid(uint index, uint length = 0xffffffff) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This essentially performs the same as operator[](), but instead of causing
|
||||||
|
* a runtime error if the index is out of bounds, it will return a null byte.
|
||||||
|
*/
|
||||||
|
char at(uint index) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Searches the ByteVector for \a pattern starting at \a offset and returns
|
||||||
|
* the offset. Returns -1 if the pattern was not found. If \a byteAlign is
|
||||||
|
* specified the pattern will only be matched if it starts on a byte divisible
|
||||||
|
* by \a byteAlign (starting from \a offset).
|
||||||
|
*/
|
||||||
|
int find(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Searches the ByteVector for \a pattern starting from either the end of the
|
||||||
|
* vector or \a offset and returns the offset. Returns -1 if the pattern was
|
||||||
|
* not found. If \a byteAlign is specified the pattern will only be matched
|
||||||
|
* if it starts on a byte divisible by \a byteAlign (starting from \a offset).
|
||||||
|
*/
|
||||||
|
int rfind(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Checks to see if the vector contains the \a pattern starting at position
|
||||||
|
* \a offset. Optionally, if you only want to search for part of the pattern
|
||||||
|
* you can specify an offset within the pattern to start from. Also, you can
|
||||||
|
* specify to only check for the first \a patternLength bytes of \a pattern with
|
||||||
|
* the \a patternLength argument.
|
||||||
|
*/
|
||||||
|
bool containsAt(const ByteVector &pattern, uint offset, uint patternOffset = 0, uint patternLength = 0xffffffff) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the vector starts with \a pattern.
|
||||||
|
*/
|
||||||
|
bool startsWith(const ByteVector &pattern) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the vector ends with \a pattern.
|
||||||
|
*/
|
||||||
|
bool endsWith(const ByteVector &pattern) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Replaces \a pattern with \a with and returns a reference to the ByteVector
|
||||||
|
* after the operation. This \e does modify the vector.
|
||||||
|
*/
|
||||||
|
ByteVector &replace(const ByteVector &pattern, const ByteVector &with);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Checks for a partial match of \a pattern at the end of the vector. It
|
||||||
|
* returns the offset of the partial match within the vector, or -1 if the
|
||||||
|
* pattern is not found. This method is particularly useful when searching for
|
||||||
|
* patterns that start in one vector and end in another. When combined with
|
||||||
|
* startsWith() it can be used to find a pattern that overlaps two buffers.
|
||||||
|
*
|
||||||
|
* \note This will not match the complete pattern at the end of the string; use
|
||||||
|
* endsWith() for that.
|
||||||
|
*/
|
||||||
|
int endsWithPartialMatch(const ByteVector &pattern) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Appends \a v to the end of the ByteVector.
|
||||||
|
*/
|
||||||
|
ByteVector &append(const ByteVector &v);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Clears the data.
|
||||||
|
*/
|
||||||
|
ByteVector &clear();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the size of the array.
|
||||||
|
*/
|
||||||
|
uint size() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Resize the vector to \a size. If the vector is currently less than
|
||||||
|
* \a size, pad the remaining spaces with \a padding. Returns a reference
|
||||||
|
* to the resized vector.
|
||||||
|
*/
|
||||||
|
ByteVector &resize(uint size, char padding = 0);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns an Iterator that points to the front of the vector.
|
||||||
|
*/
|
||||||
|
Iterator begin();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a ConstIterator that points to the front of the vector.
|
||||||
|
*/
|
||||||
|
ConstIterator begin() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns an Iterator that points to the back of the vector.
|
||||||
|
*/
|
||||||
|
Iterator end();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a ConstIterator that points to the back of the vector.
|
||||||
|
*/
|
||||||
|
ConstIterator end() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the vector is null.
|
||||||
|
*
|
||||||
|
* \note A vector may be empty without being null.
|
||||||
|
* \see isEmpty()
|
||||||
|
*/
|
||||||
|
bool isNull() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the ByteVector is empty.
|
||||||
|
*
|
||||||
|
* \see size()
|
||||||
|
* \see isNull()
|
||||||
|
*/
|
||||||
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a CRC checksum of the byte vector's data.
|
||||||
|
*/
|
||||||
|
uint checksum() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Converts the first 4 bytes of the vector to an unsigned integer.
|
||||||
|
*
|
||||||
|
* If \a mostSignificantByteFirst is true this will operate left to right
|
||||||
|
* evaluating the integer. For example if \a mostSignificantByteFirst is
|
||||||
|
* true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 ==
|
||||||
|
* 0x01000000 == 1.
|
||||||
|
*
|
||||||
|
* \see fromUInt()
|
||||||
|
*/
|
||||||
|
uint toUInt(bool mostSignificantByteFirst = true) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Converts the first 2 bytes of the vector to a short.
|
||||||
|
*
|
||||||
|
* If \a mostSignificantByteFirst is true this will operate left to right
|
||||||
|
* evaluating the integer. For example if \a mostSignificantByteFirst is
|
||||||
|
* true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1.
|
||||||
|
*
|
||||||
|
* \see fromShort()
|
||||||
|
*/
|
||||||
|
short toShort(bool mostSignificantByteFirst = true) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Converts the first 8 bytes of the vector to a (signed) long long.
|
||||||
|
*
|
||||||
|
* If \a mostSignificantByteFirst is true this will operate left to right
|
||||||
|
* evaluating the integer. For example if \a mostSignificantByteFirst is
|
||||||
|
* true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1,
|
||||||
|
* if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1.
|
||||||
|
*
|
||||||
|
* \see fromUInt()
|
||||||
|
*/
|
||||||
|
long long toLongLong(bool mostSignificantByteFirst = true) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates a 4 byte ByteVector based on \a value. If
|
||||||
|
* \a mostSignificantByteFirst is true, then this will operate left to right
|
||||||
|
* in building the ByteVector. For example if \a mostSignificantByteFirst is
|
||||||
|
* true then $00 00 00 01 == 0x00000001 == 1, if false, $01 00 00 00 ==
|
||||||
|
* 0x01000000 == 1.
|
||||||
|
*
|
||||||
|
* \see toUInt()
|
||||||
|
*/
|
||||||
|
static ByteVector fromUInt(uint value, bool mostSignificantByteFirst = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates a 2 byte ByteVector based on \a value. If
|
||||||
|
* \a mostSignificantByteFirst is true, then this will operate left to right
|
||||||
|
* in building the ByteVector. For example if \a mostSignificantByteFirst is
|
||||||
|
* true then $00 01 == 0x0001 == 1, if false, $01 00 == 0x0100 == 1.
|
||||||
|
*
|
||||||
|
* \see toShort()
|
||||||
|
*/
|
||||||
|
static ByteVector fromShort(short value, bool mostSignificantByteFirst = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates a 8 byte ByteVector based on \a value. If
|
||||||
|
* \a mostSignificantByteFirst is true, then this will operate left to right
|
||||||
|
* in building the ByteVector. For example if \a mostSignificantByteFirst is
|
||||||
|
* true then $00 00 00 01 == 0x0000000000000001 == 1, if false,
|
||||||
|
* $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1.
|
||||||
|
*
|
||||||
|
* \see toLongLong()
|
||||||
|
*/
|
||||||
|
static ByteVector fromLongLong(long long value, bool mostSignificantByteFirst = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a ByteVector based on the CString \a s.
|
||||||
|
*/
|
||||||
|
static ByteVector fromCString(const char *s, uint length = 0xffffffff);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a const refernence to the byte at \a index.
|
||||||
|
*/
|
||||||
|
const char &operator[](int index) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a reference to the byte at \a index.
|
||||||
|
*/
|
||||||
|
char &operator[](int index);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this ByteVector and \a v are equal.
|
||||||
|
*/
|
||||||
|
bool operator==(const ByteVector &v) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this ByteVector and \a v are not equal.
|
||||||
|
*/
|
||||||
|
bool operator!=(const ByteVector &v) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this ByteVector and the null terminated C string \a s
|
||||||
|
* contain the same data.
|
||||||
|
*/
|
||||||
|
bool operator==(const char *s) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this ByteVector and the null terminated C string \a s
|
||||||
|
* do not contain the same data.
|
||||||
|
*/
|
||||||
|
bool operator!=(const char *s) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this ByteVector is less than \a v. The value of the
|
||||||
|
* vectors is determined by evaluating the character from left to right, and
|
||||||
|
* in the event one vector is a superset of the other, the size is used.
|
||||||
|
*/
|
||||||
|
bool operator<(const ByteVector &v) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this ByteVector is greater than \a v.
|
||||||
|
*/
|
||||||
|
bool operator>(const ByteVector &v) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a vector that is \a v appended to this vector.
|
||||||
|
*/
|
||||||
|
ByteVector operator+(const ByteVector &v) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies ByteVector \a v.
|
||||||
|
*/
|
||||||
|
ByteVector &operator=(const ByteVector &v);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies ByteVector \a v.
|
||||||
|
*/
|
||||||
|
ByteVector &operator=(char c);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies ByteVector \a v.
|
||||||
|
*/
|
||||||
|
ByteVector &operator=(const char *data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* A static, empty ByteVector which is convenient and fast (since returning
|
||||||
|
* an empty or "null" value does not require instantiating a new ByteVector).
|
||||||
|
*/
|
||||||
|
static ByteVector null;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*
|
||||||
|
* If this ByteVector is being shared via implicit sharing, do a deep copy
|
||||||
|
* of the data and separate from the shared members. This should be called
|
||||||
|
* by all non-const subclass members.
|
||||||
|
*/
|
||||||
|
void detach();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class ByteVectorPrivate;
|
||||||
|
ByteVectorPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \relates TagLib::ByteVector
|
||||||
|
* Streams the ByteVector \a v to the output stream \a s.
|
||||||
|
*/
|
||||||
|
TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v);
|
||||||
|
|
||||||
|
#endif
|
102
Frameworks/TagLib/taglib/taglib/toolkit/tbytevectorlist.cpp
Normal file
102
Frameworks/TagLib/taglib/taglib/toolkit/tbytevectorlist.cpp
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/***************************************************************************
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
* USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "tbytevectorlist.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class ByteVectorListPrivate
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern,
|
||||||
|
int byteAlign)
|
||||||
|
{
|
||||||
|
return split(v, pattern, byteAlign, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern,
|
||||||
|
int byteAlign, int max)
|
||||||
|
{
|
||||||
|
ByteVectorList l;
|
||||||
|
|
||||||
|
uint previousOffset = 0;
|
||||||
|
for(int offset = v.find(pattern, 0, byteAlign);
|
||||||
|
offset != -1 && (max == 0 || max > int(l.size()) + 1);
|
||||||
|
offset = v.find(pattern, offset + pattern.size(), byteAlign))
|
||||||
|
{
|
||||||
|
if(offset - previousOffset > 1)
|
||||||
|
l.append(v.mid(previousOffset, offset - previousOffset));
|
||||||
|
else
|
||||||
|
l.append(ByteVector::null);
|
||||||
|
|
||||||
|
previousOffset = offset + pattern.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(previousOffset < v.size())
|
||||||
|
l.append(v.mid(previousOffset, v.size() - previousOffset));
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ByteVectorList::ByteVectorList() : List<ByteVector>()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVectorList::ByteVectorList(const ByteVectorList &l) : List<ByteVector>(l)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVectorList::~ByteVectorList()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ByteVectorList::toByteVector(const ByteVector &separator) const
|
||||||
|
{
|
||||||
|
ByteVector v;
|
||||||
|
|
||||||
|
ConstIterator it = begin();
|
||||||
|
|
||||||
|
while(it != end()) {
|
||||||
|
v.append(*it);
|
||||||
|
it++;
|
||||||
|
if(it != end())
|
||||||
|
v.append(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue