332 Commits
v1.11 ... v1.13

Author SHA1 Message Date
Urs Fleisch
15ff32b685 Version 1.13 2022-10-26 15:44:33 +02:00
Urs Fleisch
084108a908 Document replacements for deprecated functions (#1001) 2022-10-26 15:42:49 +02:00
Urs Fleisch
decc0fa50a Fix Doxygen API documentation
Since the Doxygen output changed quite a bit since the styling was adapted for
TagLib, the API documentation generated with Doxygen 1.9.1 has several problems:

- In the namespaces and classes lists, the nodes cannot be expanded,
  'N' and 'C' characters are prepended to the namespaces and classes instead
  of displaying icons.
- Class members are only accessible for the letter 'a'.
- No "Deprecated" sections are displayed (only the "TAGLIB_DEPRECATED"
  definition in the signature).
- Some things are strangely styled (e.g. an empty box on the left of the
  "Introduction" title).

Now most of the custom styling is removed to get it running again and to avoid
nasty surprises with doxygen changes.
2022-10-24 07:06:23 +02:00
Urs Fleisch
02c7e34681 MSVC: Disable warnings for internal invocations of API functions
https://raw.githubusercontent.com/microsoft/vcpkg/master/ports/taglib/msvc-disable-deprecated-warnings.patch
from Uwe Klotz (uklotzde)
2022-10-23 15:37:06 +02:00
Urs Fleisch
5f079d6992 Use GitHub Actions instead of Travis CI 2022-10-23 11:01:26 +02:00
Daniel Chabrowski
2e90ec0ef0 FileStream: seek only when length exceeds buffer size 2022-10-09 19:50:12 +02:00
Urs Fleisch
9914519d43 Update NEWS for v1.13beta 2022-09-19 18:07:31 +02:00
Urs Fleisch
f80d11ed2a MP4: Fix heap-buffer-overflow in mp4properties.cpp (#1058) 2022-09-05 06:32:53 +02:00
Urs Fleisch
4e7f844ea6 Correctly parse ID3v2.4.0 multiple strings with single BOM (#1055)
Some ID3v2.4.0 frames such as text information frames support multiple strings
separated by the termination code of the character encoding. If the encoding
is $01 UTF-16 with BOM, all strings shall have the same byte order. In the
multi strings written by TagLib, all string elements of such a multi string
have a BOM. However, I have often seen tags where a BOM exists only at the
beginning, i.e. at the start of the first string. In such a case, TagLib will
only return a list with the first string and a second empty string. This
commit will detect such cases and parse the strings without BOM according to
the BOM of the first string.
2022-08-01 09:27:35 +02:00
Stephen F. Booth
50b89ad19a Fix ID3v2 version handling for embedded frames 2022-07-24 15:28:45 +02:00
Urs Fleisch
0470c2894d Use property "WORK" instead of "CONTENTGROUP" for ID3v2 "TIT1" frame
Also use "WORK" for ASF "WM/ContentGroupDescription", as it corresponds
to "TIT1" according to
https://docs.microsoft.com/en-us/windows/win32/wmformat/id3-tag-support.
Add property "COMPILATION" for ID3v2 "TCMP" to be consistent with
MP4 "cpil".
2022-03-15 17:52:44 +01:00
James D. Smith
10721b4b41 Test for ID3v1 false positives. 2022-03-13 08:11:23 +01:00
James D. Smith
cebaf9a8e2 Utils: Fix potential ID3v1 false positive in the presence of an APE tag. 2022-03-13 08:11:23 +01:00
Urs Fleisch
197d2a684b Correctly parse MP4 non-full meta atoms (#1041)
There are m4a files with regular (non-full) meta atoms. When such
a meta atom is not correctly parsed, the subsequent atoms are not
recognized and offsets will not be adjusted when atoms are added,
which will corrupt the MP4 file.

This change will look behind the meta atom to check if the next
atom follows directly, i.e. without the four bytes with version
and flags as they exist in full atoms. In such a case, these
four bytes will not be skipped.

Witnesses of this strange format specification are
https://leo-van-stee.github.io/
https://github.com/axiomatic-systems/Bento4/blob/v1.6.0-639/Source/C%2B%2B/Core/Ap4ContainerAtom.cpp#L60
2022-03-12 07:33:32 +01:00
Urs Fleisch
e255e749e8 fileref: Adapt formatting to TagLib code style 2022-02-27 07:11:53 +01:00
Hugo Beauzée-Luyssen
a7eb7735ee fileref: Reduce variables scope 2022-02-27 07:11:53 +01:00
Hugo Beauzée-Luyssen
0de8b45612 tests: Fix stream based resolver test 2022-02-27 07:11:53 +01:00
Hugo Beauzée-Luyssen
bdd8ff2af0 fileref: Fall back on file name resolvers
when no stream resolver is available
2022-02-27 07:11:53 +01:00
Hugo Beauzée-Luyssen
82964ba176 detectByResolvers: Don't mandate an actual file to be present
The main point of IOStream is to be able to use taglib with some content
that can't be fopen()'ed, for instance a network file, or a local file
on a system that doesn't support opening a file directly through fopen
& such.
This commit adds an overload for detectByResolvers that will stick to
using an IOStream all the way.
2022-02-27 07:11:53 +01:00
Hugo Beauzée-Luyssen
f7887e7235 FileTypeResolver: Add a StreamTypeResolver interface 2022-02-27 07:11:53 +01:00
Urs Fleisch
8ab618da18 Add tests checking if looking up tags creates map entries (#931) 2022-02-09 20:07:13 +01:00
Urs Fleisch
c98fba7cc4 APE: Do not create map entry if looked up tag does not exist (#931) 2022-02-09 20:07:13 +01:00
whatdoineed2do/Ray
52bf85f8ca FLAC: Do not create map entry if looked up tag does not exist (#931) 2022-02-09 20:07:13 +01:00
Urs Fleisch
a4bb904a01 Map: Add method value() to look up without creating entry 2022-02-09 20:07:13 +01:00
Scott Wheeler
05486d00bf We don't need to export these symbols 2022-01-15 13:52:05 +01:00
Urs Fleisch
c4a0855f42 Add MP4::File::strip() to remove meta atom from file
This changes the modifications from the last commit in order to
achieve the following behavior: MP4::File::save() works in the
same way as before, i.e. it will never shrink the file and will
make space from removed items available as padding in the form of
a "free" atom. To completely remove the "meta" atom from the file,
a new method strip() is introduced, which can be used in the same
way as its MPEG::File::strip() counterpart.
2022-01-06 18:07:15 +01:00
Urs Fleisch
2cb7973162 Remove MP4 meta atom when empty tag is saved
Currently, MP4 tags can only grow. If items are removed, they are
just replaced by padding in the form of "free" atoms. This change
will remove the whole "meta" atom when an MP4 tag without items
is saved. This will make it possible, to bring the file back to
its pristine state without metadata.
2022-01-06 18:07:15 +01:00
Dzmitry Neviadomski
ff8a9ea831 Add -Wall compiler flag to Clang compilers.
Use CMAKE's `CMAKE_<LANG>_COMPILER_ID`, available from 3.0.2.
See: https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
2021-12-31 07:51:38 +01:00
ivan tkachenko
fd66b0d3b6 Add compile_commands.json to gitignore
Other entries were copied from KDE/marble repo as well.

See also: https://invent.kde.org/sdk/kdesrc-build/-/issues/86
2021-12-08 19:24:52 +01:00
Rosen Penev
f581615110 clang-tidy: replace static_cast with dynamic_cast (#1021)
* clang-tidy: replace static_cast with dynamic_cast

Found with cppcoreguidelines-pro-type-static-cast-downcast

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-07-09 21:47:36 +02:00
Rosen Penev
07eb81e88a add missing const
Avoids using a non const global variable.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-07-08 20:38:27 +02:00
Rosen Penev
c6f1e2750e use std::pair instead of 2D C array (#1020)
* use std::pair instead of 2D C array

Mostly the same. Except there's now an association between both values.

make_pair has to be used since there's no uniform initialization.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-06-21 08:16:46 +02:00
Rosen Penev
a8884c2b17 clang-tidy: don't use else after return
Found with readability-else-after-return

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-06-21 06:49:32 +02:00
Rosen Penev
76f00c5a8a clang-tidy: simplify boolean return
Found with readability-simplify-boolean-expr

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-06-21 06:49:32 +02:00
Rosen Penev
68ac7c3106 clang-tidy: use C++ casting
Found with google-readability-casting

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-06-21 06:49:32 +02:00
Rosen Penev
38d1d4c21c clang-tidy: add ending namespace comments
Found with google-readability-namespace-comments

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-06-21 06:49:32 +02:00
Rosen Penev
b77e828d4b clang-tidy: remove redundant initializations
Found with readability-redundant-member-init

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-06-21 06:49:32 +02:00
Urs Fleisch
17e299350a Detect by contents if file detected by extension is invalid (#1011)
This is the case for Opus files with an ogg extension.
2021-05-28 20:25:05 +02:00
Oleg Antonyan
1d24bd3399 Fix "error: duplicate ‘volatile’" on systems without HAVE_GCC_ATOMIC in 1.12 (#1012)
* fix error: duplicate volatile

* fix volatile ATOMIC_INT in constructor
2021-05-13 16:41:35 +02:00
bobsayshilol
4971f8fb03 ID3v2: Address review comments
Change the size check to use isEmpty() as requested.
2021-05-02 12:14:27 +02:00
bobsayshilol
d74689cb93 ASF: Bounds check the size of each header object
UBSan spotted an integer overflow on the line `dataPos += size`, so add
a bounds check to the size that we read.
2021-05-02 12:14:27 +02:00
bobsayshilol
51ae5748cb ID3v2: Return early from decode() on invalid data
The while loop in this function assumes that `data.end() - 1` is less
than `data.end()`, which isn't the case if `data` is empty since
`data.end()` can be a nullptr.
2021-05-02 12:14:27 +02:00
bobsayshilol
f2eb331696 MPC: Fix heap-buffer-overflow in readSV7()
If `data` is an allocation of only 3 bytes (MP+) then `data[3]` is a
read past the end of the buffer.
2021-05-02 12:14:27 +02:00
bobsayshilol
5f6bbb20e7 APE: Fix typo in valLength 2021-05-02 12:14:27 +02:00
bobsayshilol
03d03f782e APE: Bounds check the length of values
`pos`, `valLegnth`, and `data.size()` are all unsigned types so we have
to do a little dance to correctly bounds check them without overflow.

Without this we can get stuck in an infinite loop due to 'pos'
overflowing back to the start of the data.
2021-05-02 12:14:27 +02:00
bobsayshilol
1d3e080f04 ID3v2: Bounds check a vector's size
If the provided vector is empty then `data[0]` dereferences a nullptr,
so add a check that this won't be the case before reading the encoding.
2021-05-02 12:14:27 +02:00
bobsayshilol
3391bd80c4 FLAC: Validate the size of a read
Without this we can crash trying to dereference parts of `header`.
2021-05-02 12:14:27 +02:00
Julius Brüggemann
1644c0dd87 Add CMake option for building with ZLib 2021-03-29 20:21:59 +02:00
Scott Wheeler
85cc41082c Update to more modern macOS instructions.
Closes #1005
2021-03-22 11:36:36 +00:00
Jörg Krause
b5cd4c40e2 Drop leftovers WITH_ASF and WITH_MP4
The options WITH_ASF and WITH_MP4 where remove in commit
dd846904cb back in 2011. It's time to
remove the leftovers :-)
2021-03-06 14:54:31 +01:00
Urs Fleisch
932d45259c Fix taglib-config for cross compiling (#998) 2021-03-06 14:52:25 +01:00
Urs Fleisch
844f07d32d Make tests work with BUILD_SHARED_LIBS=ON on Windows 2021-03-06 14:52:25 +01:00
Andreas Sturmlechner
304ab20174 Install taglib.png icon into html folder structure
Signed-off-by: Andreas Sturmlechner <asturm@gentoo.org>
2021-03-06 14:52:25 +01:00
Andreas Sturmlechner
243dd863d7 Install examples after we selected to build them
Signed-off-by: Andreas Sturmlechner <asturm@gentoo.org>
2021-03-06 14:52:25 +01:00
Andreas Sturmlechner
d77e2aee0b Just set CMAKE_MODULE_PATH instead of list(APPEND), drop ENABLE_STATIC err
ENABLE_STATIC error has been there since 2014, that is long enough.

Signed-off-by: Andreas Sturmlechner <asturm@gentoo.org>
2021-03-06 14:52:25 +01:00
Andreas Sturmlechner
1e636957ab Use FeatureSummary for a nice CMake summary output
Signed-off-by: Andreas Sturmlechner <asturm@gentoo.org>
2021-03-06 14:52:25 +01:00
Andreas Sturmlechner
507a42871c Use GNUInstallDirs
Well-established CMake standard for installation directories.

Signed-off-by: Andreas Sturmlechner <asturm@gentoo.org>
2021-03-06 14:52:25 +01:00
Andreas Sturmlechner
01348fb619 Move finding ZLIB to root CMakeLists.txt
Small line decrease, but also easier to read what is happening.
Now all dependencies can be read from the root CMakeLists.txt file.

Signed-off-by: Andreas Sturmlechner <asturm@gentoo.org>
2021-03-06 14:52:25 +01:00
Andreas Sturmlechner
9e0a7f7adb Use CMake's CTest which includes BUILD_TESTING option
BUILD_TESTING is default enabled, which is a good default anyway.
Move the CppUnit check to the root CMakeLists.txt, simpler and clearer.
BUILD_TESTS is obsolete.

The need for BUILD_SHARED_LIBS=OFF for testing is not clear, it works on Linux.
But I kept it in the instructions for now.

Signed-off-by: Andreas Sturmlechner <asturm@gentoo.org>
2021-03-06 14:52:25 +01:00
Scott Wheeler
340ec9932a SVG for API doc diagrams makes a lot more sense in 2021
This also makes things look non-crappy on high-DPI monitors.
2021-02-16 12:00:52 +00:00
Urs Fleisch
c8b39449c3 Version 1.12 2021-02-15 12:23:07 +01:00
Urs Fleisch
bd254654bc Update documentation for version 1.12.0 2021-02-15 10:37:11 +01:00
Urs Fleisch
fbc3f9bbec Fix doxygen warnings 2021-02-14 18:20:29 +01:00
Urs Fleisch
99ad01e12f Fix file name resolver on Windows
The change from "fileref: Use user defined resolvers on streams"
does not work with the Windows FileName implementation, and
TestFileRef::testFileResolver fails.
2021-02-14 18:20:29 +01:00
Urs Fleisch
83aa01c6af Ogg: Set granule position to -1 if no packets finish on page (#864) 2021-02-14 10:04:03 +01:00
Urs Fleisch
4c14571647 Update version to 1.12.0 2021-01-23 09:15:32 +01:00
Urs Fleisch
f4b476a620 Add more unit tests 2021-01-18 20:31:52 +01:00
Urs Fleisch
f8d78a61f7 Merge pull request #990 from ufleisch/ufleisch/more-tests
More unit tests and bug fixes
2021-01-12 18:07:23 +01:00
Urs Fleisch
cf6c68bafc Support a consistent set of MusicBrainz properties where possible
The support for MusicBrainz properties is enhanced with "ARTISTS", "ASIN",
"RELEASECOUNTRY", "RELEASESTATUS", "RELEASETYPE", "MUSICBRAINZ_RELEASETRACKID",
"ORIGINALDATE" on APE, ASF, MP4, ID3v2, and Xiph tags.
2021-01-10 15:19:10 +01:00
Urs Fleisch
f7c24930cd Add missing iTunes properties for MP4 tags 2021-01-10 15:18:59 +01:00
Urs Fleisch
310c3bc043 Add missing 'COMPOSERSORT' property for ID3v2 tags 2021-01-10 15:18:43 +01:00
Urs Fleisch
e6c03c6de8 Create an APE tag when reading a WavPack file without tags
Now it is handled in the same way as for other tags with a
TagUnion. Without this patch, WavPack files without tags cannot
be edited via a FileRef.
2021-01-03 19:06:59 +01:00
Urs Fleisch
2c29fbeabb Use mapped roles instead of property keys for TIPL roles
For an ID3v2 "DJMIXER" property, the "DJ-MIX" TIPL role must be used.
For an ID3v2 "MIXER" property, the "MIX" TIPL role must be used.
Otherwise it will not work when reading the tag and creating
properties from the wrong TIPL roles.
2021-01-03 19:06:59 +01:00
Urs Fleisch
4828a3b925 Do not crash when removing non existing TableOfContentsFrame child 2021-01-03 19:06:59 +01:00
Urs Fleisch
794a2a0b2b Correctly construct PrivateFrame from frame data
Frame::setData() has to be used instead of PrivateFrame::setData().
2021-01-03 19:06:59 +01:00
Urs Fleisch
f32d27973f Use PCST and not TXXX:PODCAST frame for ID3v2 'PODCAST' property 2021-01-03 19:06:59 +01:00
Urs Fleisch
f74b166435 Add missing extensions to FileRef::defaultFileExtensions() 2021-01-03 19:06:59 +01:00
Urs Fleisch
c28dc78060 Add more unit tests
This not only increased the test coverage but also revealed some
bugs which are fixed in the following commits.
2021-01-03 19:06:59 +01:00
Urs Fleisch
89fb62cfb1 Update NEWS 2021-01-02 10:50:52 +01:00
Urs Fleisch
59a2994f4e Fix spelling and typos 2021-01-02 10:50:52 +01:00
Urs Fleisch
f3bdd416da Remove some DSF and DSDIFF leftovers
These can be merged back into master from the branch
add_dsf_and_dsdiff_file_formats.
2021-01-02 10:50:52 +01:00
Urs Fleisch
39f86d02e7 Merge pull request #989 from ufleisch/ufleisch/id3v2-genres
Correctly read and write multiple ID3v2.3.0 genres (#988)
2021-01-01 11:48:35 +01:00
Urs Fleisch
1a2e1d08ac Merge pull request #986 from ufleisch/ufleisch/wav-extensible-subformat
WAV: Support subformat in WAVE_FORMAT_EXTENSIBLE (#850)
2021-01-01 11:48:06 +01:00
Urs Fleisch
3f3b48353c Merge pull request #983 from ufleisch/ufleisch/flac-comment-before-picture
FLAC: Store comment block before picture block (#954)
2021-01-01 11:45:14 +01:00
Urs Fleisch
54f5c66b65 Merge pull request #981 from ufleisch/ufleisch/alac-without-bitrate
Calculate bitrate for ALAC files without it (#961)
2021-01-01 11:45:12 +01:00
Urs Fleisch
3749dd7b75 Write ID3v2.3 genres with multiple references to ID3v1 genres (#988)
As described in id3v2.3.0.txt (4.2.1, TCON), multiple genres are
only possible as references to ID3v1 genres with an optional
refinement as a text. When downgrading multiple genres from
ID3v2.4.0, they are now converted to numbers when possible and
the first genre text without ID3v1 reference is added as a
refinement. The keywords RX and CR are supported too.
2020-12-30 17:38:04 +01:00
Urs Fleisch
d602ae483e Read ID3v2.3 genres with multiple references to ID3v1 genres (#988)
As described in id3v2.3.0.txt (4.2.1, TCON), now multiple genres
are possible, e.g. "(51)(39)". Additionally, support the keywords
RX and CR.
2020-12-30 17:37:54 +01:00
Urs Fleisch
5374cb1ac4 Merge pull request #980 from ufleisch/ufleisch/wav-float-without-fact
Calculate bitrate for IEEE Float WAV files without fact chunk (#959)
2020-12-28 09:16:44 +01:00
Urs Fleisch
8a461ccedc Merge pull request #978 from ufleisch/ufleisch/wavs-with-garbage
Accept WAV files with garbage appended (#973)
2020-12-28 09:07:39 +01:00
Urs Fleisch
17c2220588 Merge pull request #963 from dbry/wavpack-fixes
WavPack fixes with test file verifying issue #962
2020-12-28 09:07:37 +01:00
Urs Fleisch
271c004b30 Merge pull request #942 from uqs/master
Fix spelling of Bebop and update Fusion and Hardcore to match Wikipedia
2020-12-28 09:07:34 +01:00
Urs Fleisch
25d9bd1814 Merge pull request #935 from jiblime/static-config
taglib-config.cmake has static libdir and includedir variables
2020-12-28 09:07:32 +01:00
Urs Fleisch
b0bb7f8c0f Merge pull request #888 from chouquette/use_resolvers_on_streams
fileref: Use user defined resolvers on streams
2020-12-28 09:07:30 +01:00
Urs Fleisch
4d3ab73d2e Merge pull request #855 from shaforostoff/broken_mp3
fix reading audioproperties for broken mp3 files
2020-12-28 09:05:31 +01:00
Urs Fleisch
ae867cbd8c ID3v1: Improve compatibility by mapping renamed genre names to codes
Also added a test to check if the renamed genre names are used and
check if using the old names still works.
2020-12-27 19:53:11 +01:00
Urs Fleisch
563fbaf82a Handle the case when MP4 file header has zero bitrate
This incorporates [6ca536b5] (mp4 properties: handle the case when
mp4 file header has zero bitrate) from PR #899 with a more accurate
bitrate calculation and a unit test.
2020-12-27 10:17:34 +01:00
Urs Fleisch
e5ad041e42 A few more corrections to genre names 2020-12-24 10:08:47 +01:00
Hugo Beauzée-Luyssen
9ca7b0c33a fileref: Use user defined resolvers on streams
Since the resolve only use the filename, there is no reason not to probe
them, as a filename might be available through the IOStream interface.
When using a ByteVectorStream, the filename will be empty and user
defined resolvers won't be probed.
2020-12-23 12:34:54 +01:00
Urs Fleisch
a00b3499b4 WavPack: Add test with non-standard sample rate 2020-12-23 07:04:51 +01:00
Urs Fleisch
d84e86da9c Clean up code to better match the TagLib style 2020-12-23 07:04:51 +01:00
Urs Fleisch
741ed4e4bf Add test for IEEE Float WAV file without fact chunk 2020-12-22 16:02:01 +01:00
Urs Fleisch
e4813f4996 Calculate bitrate for IEEE Float WAV files without fact chunk (#959)
When a WAV file with float format without a fact chunk containing
a totalSamples value is encountered, the bitrate is not calculated.
However, since all samples have the same number of bits, the
number of samples can be calculated from the size of the data chunk
and number of channels and bits per sample, as it is done in the
PCM case.
2020-12-22 15:46:48 +01:00
Urs Fleisch
1332d44ff6 WAV: Test properties of file with WAVE_FORMAT_EXTENSIBLE
uint8we.wav: http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Samples/AFsp/M1F1-uint8WE-AFsp.wav
2020-12-21 15:42:13 +01:00
Urs Fleisch
3d71ea1ad2 ALAC: Test properties of file without bitrate 2020-12-21 13:31:24 +01:00
Urs Fleisch
02c8995273 Calculate bitrate for ALAC files without it (#961)
If the "alac" atom of an MP4 file has a zero bitrate, it is calculated.
2020-12-21 12:22:25 +01:00
Urs Fleisch
7e92af6e8b FLAC: Test if picture is stored after comment 2020-12-21 11:46:10 +01:00
Urs Fleisch
7ec1127f3e FLAC: Store comment block before picture block (#954)
When the picture block is large and comes before the comment block,
Windows will no longer display the tags. This can be fixed by
storing the comment block before the picture block instead of
appending it at the end.
2020-12-21 11:09:15 +01:00
Urs Fleisch
30d839538d Make PlainFile available to all tests 2020-12-21 08:44:32 +01:00
Scott Wheeler
8f6b6ac055 Don't pull in C++11+ for one class 2020-12-20 18:38:05 +01:00
Scott Wheeler
a5f11697f7 Get things building again with C++98 2020-12-20 18:12:14 +01:00
Scott Wheeler
1721354627 Explicitly set C98 for this target
Sometime I'd like to get the lib over to C++1x, but for now, enforce
the currently in-use standard.
2020-12-20 14:22:20 +00:00
Scott Wheeler
ac7e5303a6 Merge pull request #969 from ujjwalsh/master
Adding support for Linux on power
2020-12-20 15:17:40 +01:00
Scott Wheeler
8ba246cdbe Merge pull request #984 from ufleisch/ufleisch/m4a-empty-strings-remove-items
MP4: Remove item when empty string is set (#929)
2020-12-20 15:13:58 +01:00
Scott Wheeler
6656528f18 Also allow #include <taglib/foo.h> with taglib.pc and friends
Closes #495
2020-12-20 14:09:49 +00:00
Urs Fleisch
bad2cea122 WAV: Support subformat in WAVE_FORMAT_EXTENSIBLE (#850) 2020-12-20 11:47:04 +01:00
Urs Fleisch
61d5bcfd5b MP4: Remove item when empty string is set (#929)
This will make the behavior for MP4 tags compliant to the API
documentation and consistent with other tag formats.
2020-12-13 12:37:20 +01:00
Urs Fleisch
2dd6931eee Accept WAV files with garbage appended (#973)
This will allow editing the tags of WAV files which have data
appended at the end. The corresponding unit test checks that the
original contents are still available after editing the metadata
of such files.
2020-12-06 08:56:35 +01:00
Scott Wheeler
91b00b17b2 Missing const here 2020-10-12 16:52:09 +02:00
Scott Wheeler
e116824380 Downgrade numerical genres back to ID3v2.3 format
Closes #631
2020-10-12 08:46:51 +02:00
Scott Wheeler
2db13ad8cf Add a little sanity to the formatting here 2020-10-12 08:36:57 +02:00
ujjwalsh
cd767738fc adding support for linux on power 2020-09-01 16:55:07 +00:00
David Bryant
43bc11541d correctly read very high sample rates from WavPack files 2020-07-02 17:22:03 -07:00
David Bryant
6806dc4cf2 make WavPack seekFinalIndex() more robust to false triggers 2020-07-02 16:15:51 -07:00
David Bryant
ec9c49b964 add test for WavPack DSD (issue #962) 2020-07-01 08:35:20 -07:00
David Bryant
872cafb0b9 Several fixes for WavPack files, including issue #962
Fixes to properly handle WavPack files with leading and
trailing non-audio blocks, non-standard sampling rates,
and DSD audio (introduced in WavPack 5).
2020-06-30 22:19:38 -07:00
Scott Wheeler
47342f6974 Prefer COMM frames with no description for setComment()
This creates symetry with ID3v2::Tag::comment() in preferring frames with no description
when choosing which COMM frame should be updated.  (Previously setComment() simply updated
the first COMM frame.)

Fixes #950
2020-03-27 12:14:51 +01:00
Ulrich Spörlein
5763d042a6 Fix spelling of Bebop and update Fusion and Hardcore to match Wikipedia
Source: https://en.wikipedia.org/wiki/List_of_ID3v1_Genres

Similar patches will be sent to libid3tag and ffmpeg to harmonize the
genre names and spellings.
2019-12-19 14:53:57 +01:00
jiblime
cd9e6b7502 Changed libdir/includedir variables to change based on a user's system and match syntax 2019-10-19 15:13:28 -07:00
Scott Wheeler
54508df30b Needs to be defined to nothing if none of the #if blocks match 2019-09-20 10:32:33 +02:00
Scott Wheeler
dcf0331eb1 Use newer function signatures 2019-09-19 15:23:34 +02:00
Scott Wheeler
96155f35fa Use new method signatures 2019-09-19 15:19:17 +02:00
Scott Wheeler
ebd3373d6d Correctly decode signed values
In SV7 these are a mix of signed and unsigned shorts; in SV8 they're all
signed.  Storing them as an int is fine for signed or unsigned shorts as
it's wide enough to contain either of them.

Unfortunately there are no explicit tests for SV7 at the moment; that
would be ideal to add before the next release.

CC @carewolf
2019-09-12 12:13:24 +02:00
Scott Wheeler
f3ecfa11bb Completely remove StripAll from the API
I'd imagined it being useful for calls to `strip()`, but it's not
actually used there since that's an OR-ed together set of flags 
representing which tags to strip.
2019-09-12 11:19:57 +02:00
Scott Wheeler
7082b9f66b Unsaved (and incorrect looking) field 2019-09-12 10:46:11 +02:00
Scott Wheeler
de25bc6111 StripAll should be treated as equivalent to StripOthers in save() 2019-09-12 07:57:16 +02:00
Scott Wheeler
074f30e3fa Remove DSF and DSDIFF from master to a feature branch
These can be merged back into master once they're in a more mature state.
2019-09-12 07:55:34 +02:00
Scott Wheeler
f1b40de66b Unify File::save(...) APIs between file formats that support ID3v2
Closes #922
2019-09-11 06:48:27 +02:00
Scott Wheeler
0b99cd9bac Revert switch to other static size method
This was based on a misread of the header:  at present there is no
non-static size() method, so removing the argument makes the behavior
incorrect.
2019-09-11 00:58:18 +02:00
Scott Wheeler
4668cf0f93 Missing header that should have been added in b8dc105 2019-09-11 00:42:15 +02:00
Scott Wheeler
c05fa78406 Mark deprected methods and remove internal usage
This does not put the deprecated marker on methods that will or could resolve
to the same overload, e.g.:

void foo(bool bar = true); // <-- not marked
void foo(Bar bar) // <-- since this will have a default argument in the new version
2019-09-11 00:39:37 +02:00
Scott Wheeler
b8dc105ae3 Deprecate calls to MPEG::File::save(...) that use boolean params
This uses explicit enums for e.g. the ID3v2 version, making calls more
readable:

  file.save(ID3v1 | ID3v2, StripOthers, ID3v2::v4, Duplicate);

Instead of:

  file.save(ID3v1 | ID3v2, true, 4, true);

Needs to be ported to other types, per #922
2019-09-10 22:59:07 +02:00
Scott Wheeler
fced0f46e9 Add docs for this method 2019-09-10 13:31:44 +02:00
Scott Wheeler
dc0f667a4c No tabs in TagLib 2019-09-10 13:08:11 +02:00
Scott Wheeler
085180e9a4 Require at least CMake 3 2019-09-10 12:45:36 +02:00
Scott Wheeler
ef1312d622 Add -lz to taglib.pc and taglib-config when built with zlib
Closes #872
2019-09-10 12:41:11 +02:00
StefanBruens
86c0428475 Clear valid flag for invalid Speex files
This matches the corresponding code in vorbisfile.cpp, opusfile.cpp and flagfile.cpp, and fixes taglib/taglib#902.
2019-09-10 11:44:21 +02:00
Scott Wheeler
3c78c4cfc9 Merge pull request #883 from ufleisch/riff-padding
Do not ignore non zero RIFF padding if leading to parse error (#882)
2019-09-10 11:25:46 +02:00
Scott Wheeler
c8bb6271e5 Merge pull request #917 from ufleisch/ogg-bitrate
Calculate Ogg bitrate without comment size (#874)
2019-09-10 11:14:15 +02:00
Scott Wheeler
84f7462526 Tests need C++11 2019-09-05 17:29:40 +02:00
Urs Fleisch
2f23892182 Calculate Ogg bitrate without overhead size (#874) 2019-09-02 22:14:41 +02:00
Scott Wheeler
2918602ad0 Merge pull request #910 from joerg-krause/patch-1
Drop CMAKE_SYSROOT from taglib-config
2019-08-26 23:37:24 +02:00
Scott Wheeler
c146cd7e92 Merge pull request #909 from williamjcm/patch-1
Make TagLib seach in its source dir for utf8-cpp.
2019-08-26 23:34:47 +02:00
Scott Wheeler
b124e621fe Merge pull request #912 from whatdoineed2do/m4a-track-year-equal0-bugfix
MP4 - setTrack()/setYear() accepts 0 to remove the tag
2019-08-26 23:32:44 +02:00
Scott Wheeler
044fba2921 Merge pull request #919 from jonaski/spelling
Fix spelling and typos
2019-08-26 23:26:55 +02:00
Jonas Kvinge
e72a98903f Fix spelling and typos 2019-08-26 23:23:33 +02:00
whatdoineed2do
79bc9ccf8e Call fflush() before ftruncate() to drop all buffered data (#914)
This avoids stale data presented to caller via a fread()

Current bug due to the buffered data can be seen in stripping mp3s of tags

    f.strip(ID3v1);
    f.strip(APE);

The ID3v1 tag sits at the end of file (strip calls ftruncate()) and the APE
strip performs a readFile() that would return the stream buffered/truncated data
and reinsert
2019-07-25 07:27:49 +04:30
whatdoineed2do/Ray
850a3565a4 setTrack()/setYear() accepts 0 to remove the tag as per
documentation/functionality across other tpyes (mp3/flac/...); m4a do not honour
this and instead sets the underlying value to 0.

This commit fixes this issue (#911)
2019-07-13 16:03:51 +01:00
Jörg Krause
18d424995f Drop CMAKE_SYSROOT from taglib-config
Commit d4c938cbc7 is about fixing taglib-config for proper cross-compilation. The fix is right in principle, but wrong about adding `CMAKE_SYSROOT`. The correct prefix path should be set outside of the config file as some embedded Linux distros like OpenWrt or OpenEmbedded install with a different DESTDIR, and dependent packages see a different sysroot.
2019-06-16 15:33:52 +02:00
Guillaume Jacquemin
d04db70bc6 Make TagLib seach in its source dir for utf8-cpp.
Without this change, TagLib is unusable as part of CMake projects that rely on `add_subdirectory()` for dependencies.
2019-06-01 10:19:27 +02:00
StefanBruens
ba7adc2bc2 Respect atom type when converting rate tag (#896)
* Respect atom type when converting rate tag

TagLib prior to #818 (commit ff28cf276c) read and wrote the "rate" tag as
text, and switched to reading it as integer value even when the atom class
is a text type. This breaks reading existing files, and can be avoided by
taking the atom type into account.

This fixes issue #885.

* Respect MP4::Item type when writing the rate tag

TagLib prior to #818 (commit ff28cf276c) read and wrote the "rate" tag
as text, and switched to writing the integer value of the MP4::Item.
This breaks writing from applications which supply the value as
StringList, which was the previously implemented API. Applications using
an MP4::Item(UInt) are still supported without changes on the application
side.

This is the complementary writing part for issue #885.
2019-05-31 15:51:16 +04:30
Urs Fleisch
79bb1428c0 Support ID3v2 GRP1 frame introduced with iTunes 12.5.4.42, #903. (#904) 2019-05-17 15:45:48 +04:30
Jörg Krause
7470f92a67 fix taglib-config file for cross compiling (#906) 2019-05-17 15:43:35 +04:30
Tim Malseed
6455671ece Update mp4properties.cpp (#893)
When parsing mp4 media header version 1 (mdhd) atoms, the timescale (unit) is parsed as a `LongLong` (8 bytes), but instead should be a `UInt` (4 bytes). This results in an incorrect timescale, and also pushes the offset of the duration (length) off by 4 bytes.

The end result being that the AudioProperties track length for mp4's with mdhd v1 comes back as 0.

See: https://wiki.multimedia.cx/index.php/QuickTime_container

|  Entry | Bytes (v0) | Bytes (v1) |
| :---         |     :---:      | :---: |
| size  | 4  | 4 |
| type  | 4  | 4 |
| version | 1 | 1 |
| flags | 3 | 3 |
| creation time* | 4 | **8** |
| modification time* | 4 | **8** |
| time scale | 4 | 4 |
| duration* | 4 | **8** |
| language | 2 | 2 |
| quality | 2 | 2 |
2019-03-17 08:22:19 -05:00
Tim Malseed
660748210f Minor fix for mp4 media header v0 minimum size check (#895)
Mp4 media header (mdhd) v0 atoms are a minimum of 8 bytes for size & type information, plus 24 bytes for remaining entries (`24 +8`) bytes in total, rather than (`24 + 4`).

See https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25615
2019-03-17 08:20:43 -05:00
Urs Fleisch
1cf176af61 Do not ignore non zero RIFF padding if leading to parse error (#882) 2019-02-10 08:40:20 +01:00
Stephen F. Booth
5cb589a5b8 Updated NEWS for the latest changes 2018-10-28 08:43:45 -05:00
Stephen F. Booth
a4d04e0c40 Added APE, DSF, and DFF formats to the list 2018-10-28 08:42:19 -05:00
Stephen F. Booth
4ab0891646 Added DSF and DSDIFF authors 2018-10-28 08:35:15 -05:00
Jonas Kvinge
d71398c953 Add DSF and DSDIFF file types management (#878)
* Add DSF and DSDIFF file types management

* Fixes for some build chains

* unit64_t replaced by unsigned long long, warning fixes

* Remove C++11 extension incompatible with some build chains (enumeration in a nested name specifier)

* Change typedef types (uint, ulong, ...) to standard types
remove BUILD_FRAMEWORK changes from this pull request

* Replace deprecated String::null and ByteVector::null by String() and ByteVector()
Styling update, thanks to FestusHagen

* Restyling

* Restyling to reduce length of excessively long lines

* Add to detectByExtension

* Added `isSupported(IOStream *stream)` to `DSF::File` and `DSDIFF::File`
2018-10-26 19:45:49 -05:00
evpobr
bfed3797a0 Improve CMake VISIBILITY_HIDDEN option handling (#810)
Use standard CMake's CXX_VISIBILITY_PRESET property.
2018-10-26 19:26:53 -05:00
Ola Nordstrom
e435372146 added OS X built files to .gitignore (#828) 2018-10-26 19:23:44 -05:00
Bert Wesarg
c2f544c9d1 Fill TableOfContentsFrame::toString(). (#852) 2018-10-26 19:21:18 -05:00
Scott Wheeler
8ca75f03b5 Follow TagLib's brace style 2018-10-10 19:24:44 +02:00
safu9
036a0317b9 Add support for file descriptor to FileStream (#832)
Add support for file descriptor
2018-10-10 12:25:02 -04:00
Bert Wesarg
8f6fe0b16c Don't list the description twice in UserTextIdentificationFrame::toString() (#853) 2018-10-09 18:55:02 -05:00
Scott Gayou
2c4ae870ec Fixed OOB read when loading invalid ogg flac file. (#868) (#869)
CVE-2018-11439 is caused by a failure to check the minimum length
of a ogg flac header. This header is detailed in full at:
https://xiph.org/flac/ogg_mapping.html. Added more strict checking
for entire header.
2018-10-09 18:46:55 -05:00
Urs Fleisch
d8d56d3937 Add support for cmID, purl, egid MP4 atoms (#862). (#863) 2018-04-09 08:32:05 -05:00
Nick Shaforostov
2d90d938fe fix reading audioproperties for broken mp3 files 2018-03-02 16:18:10 +01:00
Scott Wheeler
a80093167f Update links 2017-11-20 00:03:52 +01:00
Xijian Yan
249f892455 Fix crash when loading an empty mpeg file (#830)
When loading an empty file (empty.txt -> empty.mp3 ), TagLib will crash.
buffer.size() is 0, then buffer.size() - 1 is undefined (unsigned int)
2017-11-06 09:48:17 -06:00
Stephen F. Booth
cb9f07d9dc Don't assume TDRC is an instance of TextIdentificationFrame (#831)
If TDRC is encrypted, FrameFactory::createFrame() returns UnknownFrame
which causes problems in rebuildAggregateFrames() when it is assumed
that TDRC is a TextIdentificationFrame
2017-09-30 10:15:41 -05:00
Sergei Trofimovich
0b583bafd0 taglib: fix test build failure on powerpc/c++11 (#834)
powerpc is a platform with 'char' == 'unsigned char'.
As a result '-1' is not expressible in char and build fails as:

```
    # '-funsigned-char' to force test build failure on other platforms
    $ cmake .. -DBUILD_TESTS=YES -DCMAKE_CXX_FLAGS="-O2 -funsigned-char" -DCMAKE_C_FLAGS="-O2 -funsigned-char"
    ...
    $ make check
    tests/test_synchdata.cpp: In member function 'void TestID3v2SynchData::testToUIntBroken()':
    tests/test_synchdata.cpp:78:33: error: narrowing conversion of '-1' from 'int' to 'char' inside { } [-Wnarrowing]
     char data[] = { 0, 0, 0, -1 };
                                 ^
```

The fix is to expliticly cast -1 to 'char'.

Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
2017-09-18 20:06:55 -05:00
Tsuda Kageyu
4648394841 Check if mandatory header objects are present when opening ASF files.
Also removes some assignments of "this".
It feels too tricky when it is not absolutely necessary.
2017-06-13 17:22:00 +09:00
Tsuda Kageyu
e026d797e0 Use a macro to pretend virtual functions. 2017-06-13 17:01:53 +09:00
Tsuda Kageyu
eeb2f5de09 Fix some typos in debug messages. 2017-06-13 15:05:25 +09:00
Tsuda Kageyu
1792ee9db8 Update NEWS. 2017-06-12 13:07:21 +09:00
Tsuda Kageyu
1fb310ec1f Merge pull request #799 from TsudaKageyu/filetype-detection
Enable FileRef to detect file types by the actual content of a stream.
2017-06-12 13:04:15 +09:00
Tsuda Kageyu
c8bcd153fe TableOfContentsFrame depends on ByteVectorList. 2017-06-09 17:52:56 +09:00
Tsuda Kageyu
662f340f93 Merge pull request #824 from evpobr/fix-createfile2
Fix WinRT configuring
2017-06-09 08:53:25 +09:00
Tsuda Kageyu
48d8c0a808 Merge pull request #823 from TsudaKageyu/isolate-3rdparty-lib
Isolate 3rdparty library for easier maintenance.
2017-06-09 08:53:10 +09:00
evpobr
5ebd3d5276 Fix WinRT configuring
Don't rely on _WIN32_WINNT value to enable WinRT support.

if _WIN32_WINNT is not set manually, it is defaulted to SDK version. So
if you use SDK > 8 you cannot use TagLib under Win7 and lower because of
CreateFile2 function dependency.

PLATFORM_WINRT option (OFF by default) was introduced to enable WinRT
build.

Related issues: https://github.com/Microsoft/vcpkg/issues/1240
2017-06-08 19:00:37 +05:00
Tsuda Kageyu
14af861d24 Isolate 3rdparty library for easier maintenance. 2017-06-07 12:51:44 +09:00
Tsuda Kageyu
3795f277fb Update UTF8-CPP to v2.3.5. 2017-06-07 12:12:31 +09:00
Tsuda Kageyu
6045995e65 Remove an unused include directory from taglib/CMakeLists.txt. 2017-06-07 11:38:46 +09:00
Tsuda Kageyu
c2fe93c12b Restore FileRef::create() in order not to change the previous behavior. 2017-06-06 09:17:34 +09:00
Michael Helmling
ea9202d9ee Update INSTALL.md
Added a note that with MS Visual Studio 2017 one can directly open the CMake project.
2017-06-05 14:49:09 +02:00
Stephen F. Booth
3c657d1a44 Merge pull request #821 from supermihi/master
Fix Markdown syntax of INSTALL file and rename it to *.md
2017-06-05 07:37:12 -04:00
Michael Helmling
adf0f76360 Fix Markdown syntax of INSTALL file and rename it to *.md
This enables proper formatted display of the file on e.g. GitHub, increasing readability.
2017-06-05 11:09:16 +02:00
Tsuda Kageyu
682ea77c2b Mention that FileRef::create no longer works. 2017-05-31 09:41:41 +09:00
Tsuda Kageyu
15c3c756ca Update NEWS. 2017-05-31 09:28:30 +09:00
Tsuda Kageyu
4801fbb927 Merge pull request #818 from LindyBalboa/add_rate_atom_support
Add direct support for "rate" atom
2017-05-31 09:20:27 +09:00
Tsuda Kageyu
22de22b701 Fix memory leaks in a test. 2017-05-26 16:49:36 +09:00
Tsuda Kageyu
48a1a05a88 Fix MSVC warnings about unreferenced variables. 2017-05-23 17:46:16 +09:00
Tsuda Kageyu
6000a19f70 Fix the Travis-CI testing on OS X.
AppleClang 7.3 doesn't get along with CppUnit by default.
2017-05-23 17:33:22 +09:00
Conner R. Phillips
ff28cf276c Add direct support for "rate" atom
Resolves #817
2017-04-22 07:45:29 +02:00
Tsuda Kageyu
4891ee729d Remove an useless UTF-8 BOM. 2017-02-24 15:47:30 +09:00
Tsuda Kageyu
9419dab51b Allow SYLT frames to have a timestamp with no text.
Thanks to lemonboy999.
2017-02-24 15:40:30 +09:00
Tsuda Kageyu
45ee18e206 FilePrivate is responsible to delete a stream pointer instead of File.
Generally, TagLib leaves the Private classes to delete their members.
2017-02-08 17:49:48 +09:00
Tsuda Kageyu
bf7ee62dc6 Merge branch 'filetype-detection' of https://github.com/TsudaKageyu/taglib into filetype-detection 2017-02-07 22:37:13 +09:00
Tsuda Kageyu
f76b1e5429 Rename the functions 'isValidStream' to 'isSupported'.
The name 'isValidStream' is a little misleading because it doesn't check if the stream is really valid. Additionally, 'isSupported' can be naturally overloaded.
2017-02-07 22:36:56 +09:00
Tsuda Kageyu
f7b15fad20 Remove some redundant code. 2017-02-06 10:35:49 +09:00
Tsuda Kageyu
dd4adf94ce Fix wrong endian of boolean values when saving ASF files. 2017-02-06 10:06:10 +09:00
Tsuda Kageyu
d4d8410c08 Restore the layout of the copyright header of test_fileref.cpp. 2017-02-04 23:45:15 +09:00
Tsuda Kageyu
931bb042c3 Enable FileRef to detect file types by the actual content of a stream.
FileRef doesn't work with ByteVectorStream as reported at #796, since ByteVectorStream is not associated with a file name and FileRef detects file types based on file extensions.
This commit makes FileRef to work with ByteVectorStream by enabling it to detect file types based on the actual content of a stream.
2017-02-04 23:31:08 +09:00
Tsuda Kageyu
a5d9e49c49 Remove obsolete comments.
The bug mentioned in the comments are already fixed.
2017-02-04 01:31:20 +09:00
Scott Wheeler
179c175a6c Ignore warnings about OSAtomicIncrement32Barrier
The warnings suggest moving to std::atomic functions, but those are only
available in C++11.  It would be possible to switch to the C versions of
those functions, which are now provided in stdatoic.h (in C11), but
let's wait until we actually hit problems with this function and are a
few more OS versions into C11 headers being included by default.
2017-02-03 13:56:02 +00:00
Tsuda Kageyu
ba98628919 Avoid searching the same area twice in MPEG::File::previousFrameOffset(). 2017-02-01 14:23:03 +09:00
Tsuda Kageyu
87fc4012f4 Add some test cases for invalid UTF-8 sequences. 2017-01-31 14:27:23 +09:00
Tsuda Kageyu
dd5ab2a08f Fix and add some test cases for invalid surrogate pairs. 2017-01-31 14:19:30 +09:00
Tsuda Kageyu
b74ffba4b5 Update NEWS. 2017-01-31 00:21:41 +09:00
Tsuda Kageyu
4552f2c2eb Remove redundant functions in tstring.cpp.
Two versions of copyFromUTF16() are almost the same.
2017-01-30 22:38:08 +09:00
Tsuda Kageyu
6398796f95 Remove function bodies of some non-specialized template functions.
The code won't link when a wrong version is used. It's better than showing a debug message.
2017-01-30 16:11:59 +09:00
Tsuda Kageyu
2c7ac6d6a9 Add a few more test cases for invalid UTF-8 sequences. 2017-01-30 12:56:53 +09:00
Tsuda Kageyu
6a61f02f85 Merge pull request #794 from TsudaKageyu/utf8-library
Replace unicode.h/unicode.cpp by the UTF8-CPP library.
2017-01-30 12:54:43 +09:00
Tsuda Kageyu
038b52ae01 Check an invalid UTF-8 sequence consists of single char.
Single char can be an invalid UTF sequence. For example, { 0x80 } is invalid.
2017-01-30 11:35:39 +09:00
Tsuda Kageyu
598ab752bc Stop assuming that std::wstring has a contiguous and null-terminated buffer. 2017-01-30 00:36:38 +09:00
Tsuda Kageyu
922fd611ae Reduce useless memory reallocation in String::upper(). 2017-01-28 01:17:21 +09:00
Tsuda Kageyu
3d14ff74b1 Remove a duplicate test file. 2017-01-27 22:10:02 +09:00
Tsuda Kageyu
978b822774 Remove some redundant code in tstring.cpp. 2017-01-27 15:11:08 +09:00
Tsuda Kageyu
0c45c63943 Replace unicode.h/unicode.cpp by the UTF8-CPP library.
unicode.h/unicode.cpp are no longer maintained and incompatible with Debian's guideline.
UTF8-CPP is maintained on GitHub and published under the Boost Software License which is compatible with either LGPL or MPL and should go along with Debian's guideline.
2017-01-27 14:47:55 +09:00
Tsuda Kageyu
586c9bd962 Add a test for unpaired surrogate characters in a UTF-16 string. 2017-01-26 17:33:54 +09:00
Tsuda Kageyu
fc38a0e401 Remove some redundant code.
TagUnion::access() does the same thing as FLAC::File::ID3v2Tag().
2017-01-22 00:43:32 +09:00
Tsuda Kageyu
5fc5a2e81a Prefer isEmpty()/empty() to size() == 0. 2017-01-21 19:10:32 +09:00
Tsuda Kageyu
a358e87cc4 Revert useless changes accidentally committed. 2017-01-21 11:13:49 +09:00
Tsuda Kageyu
5ba8b740f9 Add missing consts. 2017-01-21 11:09:05 +09:00
Tsuda Kageyu
c4a3c3ab97 Combine two internal functions which are always used together. 2017-01-21 01:34:50 +09:00
Tsuda Kageyu
6bb92c34fa Ignore fake MPEG frame headers when seeking them. 2017-01-20 22:38:25 +09:00
Tsuda Kageyu
d2e0e55223 Efficient lookup for an ID3v2 tag in MPEG files with garbage.
This looks for an ID3v2 tag until reaching the first valid MPEG frame in O(n) time.
2017-01-20 21:14:38 +09:00
Tsuda Kageyu
d64c833359 Update NEWS. 2017-01-16 01:14:35 +09:00
Tsuda Kageyu
c9c757e0ff Merge pull request #791 from TsudaKageyu/flac-empty-seektable
Be tolerant of empty FLAC seektable blocks.
2017-01-16 01:12:07 +09:00
Tsuda Kageyu
9b548260f5 Initialize d-pointers in class member initializer list. 2017-01-16 01:05:30 +09:00
Tsuda Kageyu
406e872ac3 Always use parentheses with new. It's a bit safer. 2017-01-16 01:00:28 +09:00
Tsuda Kageyu
193cbe3b6b Initialize all the data members of ASF::Attribute. 2017-01-14 23:29:46 +09:00
Tsuda Kageyu
13be28a52c Be tolerant of empty FLAC seektable blocks. 2017-01-10 00:11:13 +09:00
Tsuda Kageyu
56a7656c2e Remove some TODO comments which are no longer necessary. 2017-01-08 01:43:04 +09:00
Michael Helmling
c97be6630e Fix #789 (typo in member doc) 2017-01-06 09:08:02 +01:00
Stephen F. Booth
6fcc690233 Merge pull request #787 from rshanmu/master
Renamed unsupported-extension.xxx and modified test
2016-12-22 12:17:12 -05:00
Ramesh Shanmugasundaram
83c72518ab Renamed unsupported-extension.xxx and modified test
The file name unsupported-extension.xxx causes issue when unpacked
taglib-xxx.gz over an NFS partition. The file extension ".xxx" is the
one NFS uses for its own purpose and hence it will not allow creation
of this file.

Hence renamed the file and modified the test cases that checks for this
file.

Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
2016-12-22 15:19:45 +00:00
Tsuda Kageyu
de87cd7736 Remove the CMake check for Boost I missed out on. 2016-12-20 12:06:21 +09:00
Tsuda Kageyu
14c3ce5737 Remove all the optional dependencies on Boost. 2016-12-20 11:54:06 +09:00
Tsuda Kageyu
ffa32b19a7 Fix the CMake check for std::atomic_int.
std::atomic_int of Visual C++ 2012 cannot be constructed with integer.
2016-12-20 11:48:14 +09:00
Tsuda Kageyu
8905e7095a Safer conversion of boolean values in ASF attributes.
Technically, boolean values in Extended Content Description Object is not necessarily be 0 or 1.
2016-12-19 10:37:10 +09:00
Tsuda Kageyu
a19a623d4b Make use of increment/decrement operators of std::atomic. 2016-12-09 10:09:31 +09:00
Tsuda Kageyu
250c59f783 Remove optional dependencies on Boost's dynamic libraries.
Using precompiled Boost libraries can lead to depending on external dynamic libraries.
2016-12-09 09:42:29 +09:00
Tsuda Kageyu
8eda5d5053 Merge pull request #784 from haoxi911/master
Fix #667: Compiled TagLib framework for OS X fails at codesign.
2016-12-09 09:00:04 +09:00
Hao Xi
b5115e3497 Fix #667: Compiled TagLib framework for OS X fails at codesign. 2016-12-08 12:53:40 +08:00
Tsuda Kageyu
36ccad2bd4 Rewrite ByteVector::replace() to run in O(n) time. 2016-12-05 11:02:59 +09:00
Tsuda Kageyu
b00a5c1aab Add a test to check if ByteVector is detached correctly when being replaced. 2016-12-05 10:15:26 +09:00
Tsuda Kageyu
f6a604f54b #include guards in CMake generated headers. 2016-12-02 17:26:43 +09:00
Tsuda Kageyu
489e2e6cbb Update NEWS. 2016-12-01 15:25:30 +09:00
Tsuda Kageyu
9336c82da3 Fix possible Ogg packet losses. 2016-12-01 11:32:01 +09:00
Tsuda Kageyu
cfbaf34597 Prevent the segment table of Ogg pages from exceeding the size limit. 2016-12-01 10:51:59 +09:00
Tsuda Kageyu
046c98230f Remove Utils::floatByteOrder() and use systemByteOrder() instead.
We can safely assume that the integer and float byte orders are the same on IEEE754 compliant systems.
2016-11-29 14:58:39 +09:00
Tsuda Kageyu
4381bd75f3 Add a test for #743/#779. 2016-11-29 10:53:33 +09:00
Tsuda Kageyu
6df61cf2af Small fix in style. 2016-11-29 10:38:11 +09:00
Tsuda Kageyu
e9ef40fe7f Merge pull request #779 from supermihi/master
Fixes #743 by not overwriting existing Xiph comment in FLAC::File::save
2016-11-28 21:03:39 +09:00
Michael Helmling
2786aa7463 Fixes #743 by not overwriting existing Xiph comment in FLAC::File::save 2016-11-27 19:17:13 +01:00
Tsuda Kageyu
d3062f3af4 A bit more tolerant check to return itself in String::substr(). 2016-11-26 13:05:14 +09:00
Stephen F. Booth
7871afec37 Merge pull request #778 from martin-flaska/optimization
String::substr optimization
2016-11-25 16:38:32 -05:00
Martin Flaska
c9a0754e3b tstring: String::substr optimization when returning itself as a substring
Use copy ctor to return in a case whole string is being returned.

The intention was to optimize String::stripWhiteSpace for no-strip case
(without any leading or trailing white space removal).

copyFromUTF16 was used in any case previously and allocated duplicate
buffer for the same string - no implicit sharing.

Signed-off-by: Martin Flaska <martin.flaska@legrand.us>
2016-11-25 15:32:26 +01:00
Martin Flaska
6cfb11bb12 test_string: Make 'stripWhiteSpace' test more complex
No string without leading/trailing spaces was used in the test.

Signed-off-by: Martin Flaska <martin.flaska@legrand.us>
2016-11-25 13:56:39 +01:00
Tsuda Kageyu
ad075a56f9 Suppress MSVC warnings in test. 2016-11-24 14:45:22 +09:00
Stephen F. Booth
f80a7c0d83 Merge pull request #776 from mathbunnyru/small_improvements
Small improvements
2016-11-23 23:31:49 -05:00
mathbunnyru
5e1d9fad31 Small fixes 2016-11-24 02:05:19 +03:00
mathbunnyru
eff28c55bf Increment fixes 2016-11-22 01:10:28 +03:00
Tsuda Kageyu
d5b9d7b8a7 Update NEWS. 2016-11-18 13:55:43 +09:00
Tsuda Kageyu
ce77fbb0e7 Merge pull request #772 from TsudaKageyu/vorbis-fields
Fix handling of lowercase 'metadata_block_picture' field
2016-11-18 13:52:38 +09:00
Tsuda Kageyu
b98a984b66 Fix handling of lowercase 'metadata_block_picture' fields in Vorbis comments.
Also refactored some redundant code for parsing pictures.
2016-11-11 00:07:32 +09:00
Tsuda Kageyu
f9a747dceb Avoid adding fields with invalid keys to Vorbis Comments.
According to the spec, '\x7F' is not allowed.
2016-11-10 23:35:14 +09:00
Tsuda Kageyu
7b8d576bde Don't decode redundant UTF-8 sequences in Win32.
Linux and OS X are working well and won't be affected.
2016-11-10 17:12:58 +09:00
Tsuda Kageyu
2651372291 Separate some tests to make them more specific. 2016-11-09 15:51:33 +09:00
Tsuda Kageyu
499f6db977 Check invalid Unicode APE keys properly. 2016-11-09 00:29:03 +09:00
Tsuda Kageyu
9d58e9f8e8 Removed a utility function which is used only at one place. 2016-11-08 23:27:55 +09:00
Tsuda Kageyu
56cd3695f7 Add README.md. 2016-11-08 22:56:42 +09:00
Tsuda Kageyu
d81d894d41 tolower() depends on the current locale.
It's much easier to write our own function than to use locales properly.
2016-11-08 21:39:53 +09:00
Tsuda Kageyu
e390cbac52 Update NEWS. 2016-11-08 21:17:00 +09:00
Tsuda Kageyu
253c61e37d Merge pull request #765 from TsudaKageyu/zero-length-atom
Proper handling of MP4 atoms with zero length.
2016-11-08 21:12:47 +09:00
Tsuda Kageyu
1848b3bc6f Merge pull request #759 from ufleisch/mp4_classical
Support new classical music frames introduced with iTunes 12.5, #758.
2016-11-08 21:12:31 +09:00
Tsuda Kageyu
aae23f3c07 Initialize all the data members of ID3v2::ChapterFrame. 2016-11-07 14:12:38 +09:00
Tsuda Kageyu
da9df1b2a8 Values of FILE_* macros are guaranteed in Win32. 2016-11-07 00:42:12 +09:00
Tsuda Kageyu
70334edd19 Add List::swap() and Map::swap(). 2016-11-04 16:43:14 +09:00
Tsuda Kageyu
f5ca097379 Proper handling of MP4 atoms with zero length.
If the size of an atom is 0, it designates the last atom which extends to the end of the file.
2016-11-02 15:44:50 +09:00
Tsuda Kageyu
eb6d058ab9 Remove a useless branch.
longLength <= LONG_MAX is always true if sizeof(long) == sizeof(long long).
2016-11-01 16:03:15 +09:00
Tsuda Kageyu
e6a69e24bc Add a common function to generate a long string to test. 2016-10-31 20:01:52 +09:00
Tsuda Kageyu
dcab8ed90e Allow ScopedFileCopy to be const. 2016-10-31 10:29:13 +09:00
Tsuda Kageyu
f5ce498182 Suppress MSVC warnings about narrowing conversions. 2016-10-30 23:51:35 +09:00
Tsuda Kageyu
ee7fa78011 Update NEWS. 2016-10-30 22:51:15 +09:00
Tsuda Kageyu
873c917081 Assume that SetFilePointerEx() and GetFileSizeEx() are always available.
This drops support for Windows 9x and NT 4.0 or older.
2016-10-30 22:36:18 +09:00
Tsuda Kageyu
d3bd8fb7ff Assume that CreateFileW() is always available.
This drops support for Windows 9x.
2016-10-30 22:25:34 +09:00
Tsuda Kageyu
005441faaa Prevent overflows, just in case. 2016-10-28 15:25:50 +09:00
Tsuda Kageyu
935534aa53 Backport a test from taglib2 branch. 2016-10-28 15:19:35 +09:00
Tsuda Kageyu
65a24bbc51 Remove some useless seek()/tell() from RIFF::File. 2016-10-28 14:22:50 +09:00
Tsuda Kageyu
711b35cc6e Encourage compilers to optimize out debug() and debugData().
It's sort of like a throwback, but I found that debug(const String &s) {} doesn't prevent a String from being constructed and the error messages from being embedded.
2016-10-28 11:19:51 +09:00
Tsuda Kageyu
d53ca6f736 Update NEWS. 2016-10-27 15:40:14 +09:00
Tsuda Kageyu
aa5f9bb221 Suppress some warnings in test. 2016-10-27 15:23:24 +09:00
Tsuda Kageyu
d2b3547254 Add a test for File::truncate(). 2016-10-27 15:15:22 +09:00
Tsuda Kageyu
06ca9a099d Check if file size <= LONG_MAX. 2016-10-27 15:10:34 +09:00
Tsuda Kageyu
8d873e4e3e Merge pull request #761 from albertofustinoni/master
WinRT compatibility
2016-10-24 22:06:35 +09:00
Alberto Fustinoni
b2fa124451 formatting 2016-10-24 21:24:53 +09:00
Alberto Fustinoni
ff5b2dc96f Whitespace 2016-10-24 21:22:57 +09:00
Alberto Fustinoni
757f5ebc96 Refactoring 2016-10-24 21:19:31 +09:00
Tsuda Kageyu
e36a9cabb9 Update NEWS. 2016-10-24 12:03:23 +09:00
Alberto Fustinoni
606f6c0e74 Better define guards 2016-10-23 23:25:16 +09:00
Alberto Fustinoni
1cc047c953 Styling 2016-10-23 20:17:49 +09:00
Alberto Fustinoni
cae4f1b804 Merge branch 'master' of https://github.com/albertofustinoni/taglib.git 2016-10-23 20:13:26 +09:00
Alberto Fustinoni
deffe83fd0 Use newer file system calls when in Windows 8+ to allow compilation as WinRT asembly 2016-10-23 12:32:16 +09:00
Tsuda Kageyu
597dcde72a Update the version to v1.11.1. 2016-10-22 02:45:52 +09:00
Tsuda Kageyu
6a96a6426a Replace a possibly non-free file in the test suite. 2016-10-22 02:11:16 +09:00
Tsuda Kageyu
69c65284a5 Update NEWS. 2016-10-22 01:06:57 +09:00
Tsuda Kageyu
97aaa0f979 Restore the ABI breakage by bringing back a removed private static variable. 2016-10-19 15:57:28 +09:00
Urs Fleisch
1b64bb0cb7 Support new classical music frames introduced with iTunes 12.5, #758.
M4A:
    ©wrk: Work (string)
    ©mvn: Movement Name (string)
    ©mvi: Movement Number (number)
    ©mvc: Movement Count (number)
    shwm: Show Work & Movement (0/1)

ID3 (2.3, 2.4; MVN, MVI for 2.2):
    MVNM: Movement Name
    MVIN: Movement Number/Count
2016-10-18 20:45:54 +02:00
Tsuda Kageyu
0dac721ce2 Update NEWS. 2016-09-26 17:48:44 +09:00
Stephen F. Booth
bbeeca6fdb Merge pull request #754 from hyperquantum/master
Fix defect in ByteVectorStream::seek when Position==End.
2016-09-15 21:11:08 -04:00
Kevin André
7e90313690 Fix defect in ByteVectorStream::seek when Position==End. 2016-09-15 16:30:16 +02:00
Tsuda Kageyu
1d3c95f692 Merge pull request #752 from evpobr/cmake-ver
Move cmake_minimum_required at the top
2016-09-12 15:56:45 +09:00
Tsuda Kageyu
8c3801f18d Merge pull request #753 from FestusHagen/fh1.m_AddBuildSharedLibsOption
Add BUILD_SHARED_LIBS option for CMake GUI.
2016-09-12 15:56:33 +09:00
Festus Hagen
c9bdd416ef Add BUILD_SHARED_LIBS option for CMake GUI. 2016-08-25 15:03:44 -04:00
evpobr
9f28e037fe Move cmake_minimum_required at the top 2016-08-20 22:37:53 +05:00
Stephen F. Booth
92c070ba9e Merge pull request #749 from jwelton/fix-typo
Fix Typo
2016-08-14 17:10:18 -04:00
Jake Welton
75e3ec73aa Change string to end offset 2016-08-14 22:02:33 +01:00
Tsuda Kageyu
3e47a036fb Update NEWS. 2016-05-14 10:46:42 +09:00
Tsuda Kageyu
9b995544e4 Fix reading table of contents frames with a lot of children. 2016-05-14 09:58:19 +09:00
231 changed files with 6731 additions and 3543 deletions

54
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: Build
on: [push, pull_request, workflow_dispatch]
env:
BUILD_TYPE: Release
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: windows-latest
cmake_extra_args: '-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Ubuntu
run: sudo apt install -y libcppunit-dev zlib1g-dev
if: matrix.os == 'ubuntu-latest'
- name: Set up macOS
run: brew install cppunit
if: matrix.os == 'macos-latest'
- name: Set up Windows
run: vcpkg install cppunit --triplet x64-windows
if: matrix.os == 'windows-latest'
- name: Configure
run: >
cmake -B${{github.workspace}}/build
-DBUILD_SHARED_LIBS=ON -DVISIBILITY_HIDDEN=ON
-DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
${{ matrix.cmake_extra_args }}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -C ${{env.BUILD_TYPE}} -V --no-tests=error
if: matrix.os != 'windows-latest'
- name: Test Windows
working-directory: ${{github.workspace}}/build
run: |
$env:Path += ";$env:VCPKG_INSTALLATION_ROOT\packages\cppunit_x64-windows\bin;$PWD\taglib\Release"
ctest -C ${{env.BUILD_TYPE}} -V --no-tests=error
if: matrix.os == 'windows-latest'

9
.gitignore vendored
View File

@@ -12,6 +12,7 @@ CMakeFiles/
*.suo
*.user
.*
!.github/workflows/
*~
/CMakeCache.txt
/Doxyfile
@@ -19,8 +20,10 @@ CMakeFiles/
/taglib.pc
/tests/test_runner
/tests/Testing
/taglib/libtag.a
/taglib_config.h
/taglib-config
/bindings/c/libtag_c.a
/bindings/c/taglib_c.pc
/bindings/c/Debug
/bindings/c/MinSizeRel
@@ -42,5 +45,11 @@ CMakeFiles/
/taglib/tag.dir/Release
/ALL_BUILD.dir
/ZERO_CHECK.dir
taglib.h.stamp
taglib.xcodeproj
CMakeScripts
/.clang-format
/compile_commands.json
.clangd
.cache
.idea

View File

@@ -1,28 +0,0 @@
language: cpp
sudo: false
os:
- linux
- osx
compiler:
- gcc
- clang
addons:
apt:
packages:
- libcppunit-dev
- zlib1g-dev
matrix:
exclude:
- os: osx
compiler: gcc
install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install cppunit; fi
script: cmake -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON . && make && make check

327
3rdparty/utf8-cpp/checked.h vendored Normal file
View File

@@ -0,0 +1,327 @@
// Copyright 2006-2016 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
#include <stdexcept>
namespace utf8
{
// Base for the exceptions that may be thrown from the library
class exception : public ::std::exception {
};
// Exceptions that may be thrown from the library functions.
class invalid_code_point : public exception {
uint32_t cp;
public:
invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
virtual const char* what() const throw() { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
class invalid_utf8 : public exception {
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const throw() { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
class invalid_utf16 : public exception {
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const throw() { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const throw() { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
throw not_enough_room();
case internal::INVALID_LEAD:
out = utf8::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it, octet_iterator end)
{
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
break;
case internal::NOT_ENOUGH_ROOM :
throw not_enough_room();
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it, octet_iterator end)
{
return utf8::next(it, end);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it, octet_iterator start)
{
// can't do much if it == start
if (it == start)
throw not_enough_room();
octet_iterator end = it;
// Go back until we hit either a lead octet or start
while (utf8::internal::is_trail(*(--it)))
if (it == start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
return utf8::peek_next(it, end);
}
/// Deprecated in versions that include "prior"
template <typename octet_iterator>
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
{
octet_iterator end = it;
while (utf8::internal::is_trail(*(--it)))
if (it == pass_start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
octet_iterator temp = it;
return utf8::next(temp, end);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end)
{
for (distance_type i = 0; i < n; ++i)
utf8::next(it, end);
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::next(first, last);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
}
else
throw invalid_utf16(static_cast<uint16_t>(cp));
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
throw invalid_utf16(static_cast<uint16_t>(cp));
result = utf8::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::next(start, end);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
octet_iterator range_start;
octet_iterator range_end;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it,
const octet_iterator& rangestart,
const octet_iterator& rangeend) :
it(octet_it), range_start(rangestart), range_end(rangeend)
{
if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position");
}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::next(temp, range_end);
}
bool operator == (const iterator& rhs) const
{
if (range_start != rhs.range_start || range_end != rhs.range_end)
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
utf8::next(it, range_end);
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
utf8::next(it, range_end);
return temp;
}
iterator& operator -- ()
{
utf8::prior(it, range_start);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::prior(it, range_start);
return temp;
}
}; // class iterator
} // namespace utf8
#endif //header guard

332
3rdparty/utf8-cpp/core.h vendored Normal file
View File

@@ -0,0 +1,332 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include <iterator>
namespace utf8
{
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
// You may need to change them to match your system.
// These typedefs have the same names as ones from cstdint, or boost/cstdint
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Helper code - not intended to be directly called by the library users. May be changed at any time
namespace internal
{
// Unicode constants
// Leading (high) surrogates: 0xd800 - 0xdbff
// Trailing (low) surrogates: 0xdc00 - 0xdfff
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
// Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
template<typename octet_type>
inline uint8_t mask8(octet_type oc)
{
return static_cast<uint8_t>(0xff & oc);
}
template<typename u16_type>
inline uint16_t mask16(u16_type oc)
{
return static_cast<uint16_t>(0xffff & oc);
}
template<typename octet_type>
inline bool is_trail(octet_type oc)
{
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
}
template <typename u16>
inline bool is_lead_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
}
template <typename u16>
inline bool is_trail_surrogate(u16 cp)
{
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u16>
inline bool is_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
inline typename std::iterator_traits<octet_iterator>::difference_type
sequence_length(octet_iterator lead_it)
{
uint8_t lead = utf8::internal::mask8(*lead_it);
if (lead < 0x80)
return 1;
else if ((lead >> 5) == 0x6)
return 2;
else if ((lead >> 4) == 0xe)
return 3;
else if ((lead >> 3) == 0x1e)
return 4;
else
return 0;
}
template <typename octet_difference_type>
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
{
if (cp < 0x80) {
if (length != 1)
return true;
}
else if (cp < 0x800) {
if (length != 2)
return true;
}
else if (cp < 0x10000) {
if (length != 3)
return true;
}
return false;
}
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
/// Helper for get_sequence_x
template <typename octet_iterator>
utf_error increase_safely(octet_iterator& it, octet_iterator end)
{
if (++it == end)
return NOT_ENOUGH_ROOM;
if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE;
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
// Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it;
uint32_t cp = 0;
// Determine the sequence length based on the lead octet
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
const octet_difference_type length = utf8::internal::sequence_length(it);
// Get trail octets and calculate the code point
utf_error err = UTF8_OK;
switch (length) {
case 0:
return INVALID_LEAD;
case 1:
err = utf8::internal::get_sequence_1(it, end, cp);
break;
case 2:
err = utf8::internal::get_sequence_2(it, end, cp);
break;
case 3:
err = utf8::internal::get_sequence_3(it, end, cp);
break;
case 4:
err = utf8::internal::get_sequence_4(it, end, cp);
break;
}
if (err == UTF8_OK) {
// Decoding succeeded. Now, security checks...
if (utf8::internal::is_code_point_valid(cp)) {
if (!utf8::internal::is_overlong_sequence(cp, length)){
// Passed! Return here.
code_point = cp;
++it;
return UTF8_OK;
}
else
err = OVERLONG_SEQUENCE;
}
else
err = INVALID_CODE_POINT;
}
// Failure branch - restore the original value of the iterator
it = original_it;
return err;
}
template <typename octet_iterator>
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
uint32_t ignored;
return utf8::internal::validate_next(it, end, ignored);
}
} // namespace internal
/// The library API - functions intended to be called by the users
// Byte order mark
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
template <typename octet_iterator>
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
{
octet_iterator result = start;
while (result != end) {
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
if (err_code != internal::UTF8_OK)
return result;
}
return result;
}
template <typename octet_iterator>
inline bool is_valid(octet_iterator start, octet_iterator end)
{
return (utf8::find_invalid(start, end) == end);
}
template <typename octet_iterator>
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
{
return (
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
);
}
//Deprecated in release 2.3
template <typename octet_iterator>
inline bool is_bom (octet_iterator it)
{
return (
(utf8::internal::mask8(*it++)) == bom[0] &&
(utf8::internal::mask8(*it++)) == bom[1] &&
(utf8::internal::mask8(*it)) == bom[2]
);
}
} // namespace utf8
#endif // header guard

View File

@@ -4,6 +4,8 @@ Lukas Lalinsky <lalinsky@gmail.com>
Implementation of multiple new file formats, many bug fixes, maintainer
Tsuda Kageyu <tsuda.kageyu@gmail.com>
A lot of bug fixes and performance improvements, maintainer.
Stephen F. Booth <me@sbooth.org>
DSF metadata implementation, bug fixes, maintainer.
Ismael Orenstein <orenstein@kde.org>
Xing header implementation
Allan Sandfeld Jensen <kde@carewolf.org>
@@ -12,6 +14,10 @@ Teemu Tervo <teemu.tervo@gmx.net>
Numerous bug reports and fixes
Mathias Panzenböck <grosser.meister.morti@gmx.net>
Mod, S3M, IT and XM metadata implementations
Damien Plisson <damien78@audirvana.com>
DSDIFF metadata implementation
Urs Fleisch <ufleisch@users.sourceforge.net>
Bug fixes, maintainer.
Please send all patches and questions to taglib-devel@kde.org rather than to
individual developers!

View File

@@ -1,17 +1,22 @@
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
project(taglib)
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
if(NOT ${CMAKE_VERSION} VERSION_LESS 2.8.12)
cmake_policy(SET CMP0022 OLD)
include(CTest)
include(FeatureSummary)
include(GNUInstallDirs)
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
if(APPLE)
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
if(BUILD_FRAMEWORK)
set(BUILD_SHARED_LIBS ON)
#set(CMAKE_MACOSX_RPATH 1)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
endif()
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
if(DEFINED ENABLE_STATIC)
message(FATAL_ERROR "This option is no longer available, use BUILD_SHARED_LIBS instead")
endif()
if(NOT BUILD_SHARED_LIBS)
add_definitions(-DTAGLIB_STATIC)
endif()
@@ -27,40 +32,38 @@ if(ENABLE_CCACHE)
endif()
option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF)
if(VISIBILITY_HIDDEN)
add_definitions(-fvisibility=hidden)
endif()
option(BUILD_TESTS "Build the test suite" OFF)
option(BUILD_EXAMPLES "Build the examples" OFF)
option(BUILD_BINDINGS "Build the bindings" ON)
option(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF)
option(PLATFORM_WINRT "Enable WinRT support" OFF)
if(PLATFORM_WINRT)
add_definitions(-DPLATFORM_WINRT)
endif()
add_definitions(-DHAVE_CONFIG_H)
set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/")
## the following are directories where stuff will be installed to
set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)")
set(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries")
set(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The subdirectory to the binaries prefix (default prefix/bin)")
set(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})")
set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix")
if(APPLE)
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
if(MSVC AND ENABLE_STATIC_RUNTIME)
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
if(MSVC)
if(ENABLE_STATIC_RUNTIME)
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
endif()
# Disable warnings for internal invocations of API functions
# that have been marked with TAGLIB_DEPRECATED
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4996
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996")
endif()
# Read version information from file taglib/toolkit/taglib.h into variables
@@ -89,9 +92,9 @@ endif()
# 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0.
# 3. If any interfaces have been added since the last public release, then increment age.
# 4. If any interfaces have been removed since the last public release, then set age to 0.
set(TAGLIB_SOVERSION_CURRENT 17)
set(TAGLIB_SOVERSION_CURRENT 20)
set(TAGLIB_SOVERSION_REVISION 0)
set(TAGLIB_SOVERSION_AGE 16)
set(TAGLIB_SOVERSION_AGE 19)
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
@@ -99,36 +102,46 @@ math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}")
include(ConfigureChecks.cmake)
# Determine whether zlib is installed.
option(WITH_ZLIB "Build with ZLIB" ON)
if(WITH_ZLIB)
if(NOT ZLIB_SOURCE)
find_package(ZLIB)
if(ZLIB_FOUND)
set(HAVE_ZLIB 1)
set(ZLIB_LIBRARIES_FLAGS -lz)
else()
set(HAVE_ZLIB 0)
endif()
endif()
if(NOT HAVE_ZLIB AND ZLIB_SOURCE)
set(HAVE_ZLIB 1)
set(HAVE_ZLIB_SOURCE 1)
endif()
else()
set(HAVE_ZLIB 0)
endif()
if(NOT WIN32)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config" DESTINATION "${BIN_INSTALL_DIR}")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config" @ONLY)
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config" DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
if(WIN32)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmd.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd" DESTINATION "${BIN_INSTALL_DIR}")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd" DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
if(NOT BUILD_FRAMEWORK)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/taglib.pc" DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
endif()
if(NOT HAVE_ZLIB AND ZLIB_SOURCE)
set(HAVE_ZLIB 1)
set(HAVE_ZLIB_SOURCE 1)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/taglib.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
configure_file(config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h")
if(WITH_ASF)
set(TAGLIB_WITH_ASF TRUE)
endif()
if(WITH_MP4)
set(TAGLIB_WITH_MP4 TRUE)
endif()
option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF)
if(TRACE_IN_RELEASE)
set(TRACE_IN_RELEASE TRUE)
@@ -142,9 +155,13 @@ if(BUILD_BINDINGS)
add_subdirectory(bindings)
endif()
if(BUILD_TESTS AND NOT BUILD_SHARED_LIBS)
enable_testing()
add_subdirectory(tests)
if(BUILD_TESTING)
find_package(CppUnit)
if(CppUnit_FOUND)
add_subdirectory(tests)
else()
message(WARNING "BUILD_TESTING requested, but CppUnit not found, skipping tests.")
endif()
endif()
if(BUILD_EXAMPLES)
@@ -152,7 +169,6 @@ if(BUILD_EXAMPLES)
endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
file(COPY doc/taglib.png DESTINATION doc)
add_custom_target(docs doxygen)
# uninstall target
@@ -161,3 +177,5 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_C
if(NOT TARGET uninstall)
add_custom_target(uninstall COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
endif()
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)

View File

@@ -34,77 +34,49 @@ if(NOT ${SIZEOF_DOUBLE} EQUAL 8)
message(FATAL_ERROR "TagLib requires that double is 64-bit wide.")
endif()
# Enable check_cxx_source_compiles() to work with Boost "header-only" libraries.
find_package(Boost)
if(Boost_FOUND)
set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES};${Boost_INCLUDE_DIRS}")
endif()
# Determine which kind of atomic operations your compiler supports.
check_cxx_source_compiles("
#include <atomic>
int main() {
std::atomic<unsigned int> x;
x.fetch_add(1);
x.fetch_sub(1);
return 0;
}
" HAVE_STD_ATOMIC)
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_GCC_ATOMIC)
if(NOT HAVE_STD_ATOMIC)
find_package(Boost COMPONENTS atomic)
if(Boost_ATOMIC_FOUND)
set(HAVE_BOOST_ATOMIC 1)
else()
set(HAVE_BOOST_ATOMIC 0)
endif()
if(NOT HAVE_BOOST_ATOMIC)
check_cxx_source_compiles("
if(NOT HAVE_GCC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
return 0;
}
" HAVE_GCC_ATOMIC)
" HAVE_MAC_ATOMIC)
if(NOT HAVE_GCC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
if(NOT HAVE_MAC_ATOMIC)
check_cxx_source_compiles("
#include <windows.h>
int main() {
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
return 0;
}
" HAVE_MAC_ATOMIC)
" HAVE_WIN_ATOMIC)
if(NOT HAVE_MAC_ATOMIC)
check_cxx_source_compiles("
#include <windows.h>
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <ia64intrin.h>
int main() {
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_WIN_ATOMIC)
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <ia64intrin.h>
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_IA64_ATOMIC)
endif()
endif()
" HAVE_IA64_ATOMIC)
endif()
endif()
endif()
@@ -112,69 +84,57 @@ endif()
# Determine which kind of byte swap functions your compiler supports.
check_cxx_source_compiles("
#include <boost/endian/conversion.hpp>
int main() {
boost::endian::endian_reverse(static_cast<uint16_t>(1));
boost::endian::endian_reverse(static_cast<uint32_t>(1));
boost::endian::endian_reverse(static_cast<uint64_t>(1));
__builtin_bswap16(0);
__builtin_bswap32(0);
__builtin_bswap64(0);
return 0;
}
" HAVE_BOOST_BYTESWAP)
" HAVE_GCC_BYTESWAP)
if(NOT HAVE_BOOST_BYTESWAP)
if(NOT HAVE_GCC_BYTESWAP)
check_cxx_source_compiles("
#include <byteswap.h>
int main() {
__builtin_bswap16(0);
__builtin_bswap32(0);
__builtin_bswap64(0);
__bswap_16(0);
__bswap_32(0);
__bswap_64(0);
return 0;
}
" HAVE_GCC_BYTESWAP)
" HAVE_GLIBC_BYTESWAP)
if(NOT HAVE_GCC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
check_cxx_source_compiles("
#include <byteswap.h>
#include <stdlib.h>
int main() {
__bswap_16(0);
__bswap_32(0);
__bswap_64(0);
_byteswap_ushort(0);
_byteswap_ulong(0);
_byteswap_uint64(0);
return 0;
}
" HAVE_GLIBC_BYTESWAP)
" HAVE_MSC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
if(NOT HAVE_MSC_BYTESWAP)
check_cxx_source_compiles("
#include <stdlib.h>
#include <libkern/OSByteOrder.h>
int main() {
_byteswap_ushort(0);
_byteswap_ulong(0);
_byteswap_uint64(0);
OSSwapInt16(0);
OSSwapInt32(0);
OSSwapInt64(0);
return 0;
}
" HAVE_MSC_BYTESWAP)
" HAVE_MAC_BYTESWAP)
if(NOT HAVE_MSC_BYTESWAP)
if(NOT HAVE_MAC_BYTESWAP)
check_cxx_source_compiles("
#include <libkern/OSByteOrder.h>
#include <sys/endian.h>
int main() {
OSSwapInt16(0);
OSSwapInt32(0);
OSSwapInt64(0);
swap16(0);
swap32(0);
swap64(0);
return 0;
}
" HAVE_MAC_BYTESWAP)
if(NOT HAVE_MAC_BYTESWAP)
check_cxx_source_compiles("
#include <sys/endian.h>
int main() {
swap16(0);
swap32(0);
swap64(0);
return 0;
}
" HAVE_OPENBSD_BYTESWAP)
endif()
" HAVE_OPENBSD_BYTESWAP)
endif()
endif()
endif()
@@ -216,33 +176,7 @@ check_cxx_source_compiles("
}
" HAVE_ISO_STRDUP)
# Determine whether zlib is installed.
if(NOT ZLIB_SOURCE)
find_package(ZLIB)
if(ZLIB_FOUND)
set(HAVE_ZLIB 1)
else()
set(HAVE_ZLIB 0)
endif()
if(NOT HAVE_ZLIB)
find_package(Boost COMPONENTS iostreams zlib)
if(Boost_IOSTREAMS_FOUND AND Boost_ZLIB_FOUND)
set(HAVE_BOOST_ZLIB 1)
else()
set(HAVE_BOOST_ZLIB 0)
endif()
endif()
# Detect WinRT mode
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
set(PLATFORM WINRT 1)
endif()
# Determine whether CppUnit is installed.
if(BUILD_TESTS AND NOT BUILD_SHARED_LIBS)
find_package(CppUnit)
if(NOT CppUnit_FOUND)
message(STATUS "CppUnit not found, disabling tests.")
set(BUILD_TESTS OFF)
endif()
endif()

View File

@@ -1,37 +1,79 @@
# Doxyfile 1.3.4
# Doxyfile 1.9.1
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = TagLib
PROJECT_NUMBER = ${TAGLIB_LIB_VERSION_STRING}
PROJECT_BRIEF =
PROJECT_LOGO = @CMAKE_SOURCE_DIR@/doc/taglib.svg
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
OUTPUT_TEXT_DIRECTION = None
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
PYTHON_DOCSTRING = YES
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_PRIV_VIRTUAL = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = NO
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
RESOLVE_UNNAMED_PARAMS = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
@@ -39,172 +81,267 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = YES
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
GENERATE_DEPRECATEDLIST= NO
ENABLED_SECTIONS =
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = @CMAKE_SOURCE_DIR@/taglib
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.h \
*.hh \
*.H
RECURSIVE = YES
EXCLUDE =
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# configuration options related to source browsing
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = NO
CLANG_ADD_INC_PATHS = YES
CLANG_OPTIONS =
CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER = @CMAKE_SOURCE_DIR@/doc/api-header.html
HTML_FOOTER = @CMAKE_SOURCE_DIR@/doc/api-footer.html
HTML_STYLESHEET = @CMAKE_SOURCE_DIR@/doc/taglib-api.css
HTML_ALIGN_MEMBERS = YES
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = YES
ENUM_VALUES_PER_LINE = 4
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
FORMULA_MACROFILE =
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = NO
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = letter
EXTRA_PACKAGES =
LATEX_HEADER =
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# configuration options related to the RTF output
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# configuration options related to the man page output
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = DO_NOT_DOCUMENT \
DOXYGEN \
WITH_MP4 \
WITH_ASF
EXPAND_AS_DEFINED =
DOXYGEN
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::addtions related to external references
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
DOT_UML_DETAILS = NO
DOT_WRAP_THRESHOLD = 17
TEMPLATE_RELATIONS = YES
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = svg
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 100
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::addtions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

159
INSTALL
View File

@@ -1,159 +0,0 @@
TagLib Installation
===================
TagLib uses the CMake build system. As a user, you will most likely want to
build TagLib in release mode and install it into a system-wide location.
This can be done using the following commands:
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release .
make
sudo make install
In order to build the included examples, use the BUILD_EXAMPLES option:
cmake -DBUILD_EXAMPLES=ON [...]
See http://www.cmake.org/cmake/help/runningcmake.html for generic help on
running CMake.
Mac OS X
--------
On Mac OS X, you might want to build a framework that can be easily integrated
into your application. If you set the BUILD_FRAMEWORK option on, it will compile
TagLib as a framework. For example, the following command can be used to build
an Universal Binary framework with Mac OS X 10.4 as the deployment target:
cmake -DCMAKE_BUILD_TYPE=Release \
-DBUILD_FRAMEWORK=ON \
-DCMAKE_C_COMPILER=/usr/bin/gcc-4.0 \
-DCMAKE_CXX_COMPILER=/usr/bin/c++-4.0 \
-DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.4u.sdk/ \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.4 \
-DCMAKE_OSX_ARCHITECTURES="ppc;i386;x86_64"
For a 10.6 Snow Leopard static library with both 32-bit and 64-bit code, use:
cmake -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.6 \
-DCMAKE_OSX_ARCHITECTURES="i386;x86_64" \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_INSTALL_PREFIX="<folder you want to build to>"
After 'make', and 'make install', add libtag.a to your XCode project, and add
the include folder to the project's User Header Search Paths.
Windows
-------
It's Windows ... Systems vary!
This means you need to adjust things to suit your system, especially paths.
Tested with:
Microsoft Visual Studio 2010
Gcc by mingw-w64.sf.net v4.6.3 (Strawberry Perl 32b)
MinGW32-4.8.0
Requirements:
1. Tool chain, Build Environment, Whatever ya want to call it ...
Installed and working.
2. CMake program. (Available at: www.cmake.org)
Installed and working.
Optional:
1. Zlib library.
Available in some Tool Chains, Not all.
Search the web, Take your choice.
Useful configuration options used with CMake (GUI and/or Command line):
Any of the ZLIB_ variables may be used at the command line, ZLIB_ROOT is only
available on the Command line.
ZLIB_ROOT= Where to find ZLib's root directory.
Assumes parent of: \include and \lib.
ZLIB_INCLUDE_DIR= Where to find ZLib's Include directory.
ZLIB_LIBRARY= Where to find ZLib's Library.
ZLIB_SOURCE= Where to find ZLib's Source Code.
Alternative to ZLIB_INCLUDE_DIR and ZLIB_LIBRARY.
CMAKE_INSTALL_PREFIX= Where to install Taglib.
CMAKE_BUILD_TYPE= Release, Debug, etc ... (Not available in MSVC)
The easiest way is at the Command Prompt.
MSVS Command Prompt for MSVS Users.
(Batch file and/or Shortcuts are your friends)
1. Build the Makefiles:
Replace "GENERATOR" with your needs.
For MSVS : "Visual Studio X" where X is the single or two digit version.
For MinGW: "MinGW Makefiles"
C:\GitRoot\taglib> cmake -G "GENERATOR" -DCMAKE_INSTALL_PREFIX=C:\Libraries\taglib
Or use the CMake GUI:
1. Open CMake GUI.
2. Set Paths.
"Where is the source code" and "Where to build the binaries"
Example, Both would be: C:\GitRoot\taglib
3. Tick: Advanced
4. Select: Configure
5. Select: Generator
6. Tick: Use default native compilers
7. Select: Finish
Wait until done.
5. If using ZLib, Scroll down.
(to the bottom of the list of options ... should go over them all)
1. Edit: ZLIB_INCLUDE_DIR
2. Edit: ZLIB_LIBRARY
6. Select: Generate
2. Build the project:
MSVS:
C:\GitRoot\taglib> msbuild all_build.vcxproj /p:Configuration=Release
OR (Depending on MSVS version or personal choice)
C:\GitRoot\taglib> devenv all_build.vcxproj /build Release
MinGW:
C:\GitRoot\taglib> gmake
OR (Depending on MinGW install)
C:\GitRoot\taglib> mingw32-make
Or in the MSVS GUI:
1. Open MSVS.
2. Open taglib solution.
3. Set build type to: Release (look in the tool bars)
2. Hit F7 to build the solution. (project)
3. Install the project:
(Change 'install' to 'uninstall' to uninstall the project)
MSVS:
C:\GitRoot\taglib> msbuild install.vcxproj
OR (Depending on MSVC version or personal choice)
C:\GitRoot\taglib> devenv install.vcxproj
MinGW:
C:\GitRoot\taglib> gmake install
OR (Depending on MinGW install)
C:\GitRoot\taglib> mingw32-make install
Or in the MSVS GUI:
1. Open project.
2. Open Solution Explorer.
3. Right Click: INSTALL
4. Select: Project Only
5. Select: Build Only INSTALL
To build a static library, set the following two options with CMake.
-DBUILD_SHARED_LIBS=OFF -DENABLE_STATIC_RUNTIME=ON
Including ENABLE_STATIC_RUNTIME=ON indicates you want TagLib built using the
static runtime library, rather than the DLL form of the runtime.
Unit Tests
----------
If you want to run the test suite to make sure TagLib works properly on your
system, you need to have cppunit installed. To build the tests, include
the option -DBUILD_TESTS=on when running cmake.
The test suite has a custom target in the build system, so you can run
the tests using make:
make check

228
INSTALL.md Normal file
View File

@@ -0,0 +1,228 @@
TagLib Installation
===================
TagLib uses the CMake build system. As a user, you will most likely want to
build TagLib in release mode and install it into a system-wide location.
This can be done using the following commands:
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release .
make
sudo make install
In order to build the included examples, use the `BUILD_EXAMPLES` option:
cmake -DBUILD_EXAMPLES=ON [...]
If you want to build TagLib without ZLib, you can use
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release -DWITH_ZLIB=OFF .
make
sudo make install
See http://www.cmake.org/cmake/help/runningcmake.html for generic help on
running CMake.
Mac OS X
--------
On Mac OS X, you might want to build a framework that can be easily integrated
into your application. If you set the BUILD_FRAMEWORK option on, it will compile
TagLib as a framework. For example, the following command can be used to build
a framework with Mac OS X 10.10 as the deployment target:
mkdir build; cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF \
-DBUILD_FRAMEWORK=ON \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.10 \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
make
For a 10.10 static library, use:
mkdir build; cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.10 \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
make
After `make`, and `make install`, add `libtag.` to your XCode project, and add
the include folder to the project's User Header Search Paths.
Windows
-------
It's Windows ... Systems vary!
This means you need to adjust things to suit your system, especially paths.
Tested with:
* Microsoft Visual Studio 2010, 2015, 2017
* Microsoft C++ Build Tools 2015, 2017 (standalone packages not requiring Visual Studio)
* GCC by mingw-w64.sf.net v4.6.3 (Strawberry Perl 32b)
* MinGW32-4.8.0
Requirements:
* Tool chain, build environment, whatever ya want to call it ...
Installed and working.
* CMake program. (Available at: www.cmake.org)
Installed and working.
Optional:
* Zlib library.
Available in some tool chains, not all.
Search the web, take your choice.
Useful configuration options used with CMake (GUI and/or command line):
Any of the `ZLIB_` variables may be used at the command line, `ZLIB_ROOT` is only
available on the command line.
| option | description |
| ----------------------- | ----------- |
| `WITH_ZLIB=` | Whether to build with ZLib |
| `ZLIB_ROOT=` | Where to find ZLib's root directory. Assumes parent of: `\include` and `\lib.`|
| `ZLIB_INCLUDE_DIR=` | Where to find ZLib's Include directory.|
| `ZLIB_LIBRARY=` | Where to find ZLib's Library.
| `ZLIB_SOURCE=` | Where to find ZLib's Source Code. Alternative to `ZLIB_INCLUDE_DIR` and `ZLIB_LIBRARY`.
| `CMAKE_INSTALL_PREFIX=` | Where to install Taglib. |
| `CMAKE_BUILD_TYPE=` | Release, Debug, etc ... (Not available in MSVC) |
The easiest way is at the command prompt (Visual C++ command prompt for MSVS users batch file and/or shortcuts are your friends).
1. **Build the Makefiles:**
Replace "GENERATOR" with your needs.
* For MSVS: `Visual Studio XX YYYY`, e.g. `Visual Studio 14 2015`.
**Note**: As Visual Studio 2017 supports CMake, you can skip this step and open the taglib
folder in VS instead.
* For MinGW: `MinGW Makefiles`
C:\GitRoot\taglib> cmake -G "GENERATOR" -DCMAKE_INSTALL_PREFIX=C:\Libraries\taglib
Or use the CMake GUI:
1. Open CMake GUI.
2. Set paths: *Where is the source code* and *Where to build the binaries*.
In the example, both would be: `C:\GitRoot\taglib`
3. Tick: Advanced
4. Select: Configure
5. Select: Generator
6. Tick: Use default native compilers
7. Select: Finish
Wait until done.
8. If using ZLib, Scroll down.
(to the bottom of the list of options ... should go over them all)
1. Edit: `ZLIB_INCLUDE_DIR`
2. Edit: `ZLIB_LIBRARY`
9. Select: Generate
2. **Build the project**
* MSVS:
C:\GitRoot\taglib> msbuild all_build.vcxproj /p:Configuration=Release
OR (Depending on MSVS version or personal choice)
C:\GitRoot\taglib> devenv all_build.vcxproj /build Release
OR in the MSVS GUI:
1. Open MSVS.
2. Open taglib solution.
3. Set build type to: Release (look in the tool bars)
2. Hit F7 to build the solution. (project)
* MinGW:
C:\GitRoot\taglib> gmake
OR (Depending on MinGW install)
C:\GitRoot\taglib> mingw32-make
3. **Install the project**
(Change `install` to `uninstall` to uninstall the project)
* MSVS:
C:\GitRoot\taglib> msbuild install.vcxproj
OR (Depending on MSVC version or personal choice)
C:\GitRoot\taglib> devenv install.vcxproj
Or in the MSVS GUI:
1. Open project.
2. Open Solution Explorer.
3. Right Click: INSTALL
4. Select: Project Only
5. Select: Build Only INSTALL
* MinGW:
C:\GitRoot\taglib> gmake install
OR (Depending on MinGW install)
C:\GitRoot\taglib> mingw32-make install
To build a static library, set the following two options with CMake:
-DBUILD_SHARED_LIBS=OFF -DENABLE_STATIC_RUNTIME=ON
Including `ENABLE_STATIC_RUNTIME=ON` indicates you want TagLib built using the
static runtime library, rather than the DLL form of the runtime.
Unit Tests
----------
If you want to run the test suite to make sure TagLib works properly on your
system, you need to have cppunit installed. To build the tests, include
the option `-DBUILD_TESTING=ON` when running cmake.
The test suite has a custom target in the build system, so you can run
the tests using make:
make check
Windows MinGW:
* Get cppunit from https://www.freedesktop.org/wiki/Software/cppunit/
* Build it for MinGW:
- `./autogen.sh`
- `./configure --disable-shared`
- `mingw32-make; mingw32-make install DESTDIR=/path/to/install/dir`
* Build TagLib with testing enabled:
- ```
cmake -G "MinGW Makefiles" -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_SHARED_LIBS=OFF \
-DCPPUNIT_INCLUDE_DIR=/path/to/cppunit/include \
-DCPPUNIT_LIBRARIES=/path/to/cppunit/lib/libcppunit.a \
-DCPPUNIT_INSTALLED_VERSION=1.15.1
```
- `mingw32-make`
- `mingw32-make check`
Windows MSVS:
* Get cppunit from https://www.freedesktop.org/wiki/Software/cppunit/
* Build it in Visual Studio:
- Open examples/examples2008.sln, convert all, do not overwrite.
- Set architecture to x64, build configuration, e.g. Debug DLL.
- It may fail, but the needed libraries should be available in src\cppunit\DebugDll.
* Build TagLib with testing enabled:
- ```
cmake -G "Visual Studio 16 2019" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON
-DBUILD_SHARED_LIBS=OFF -DENABLE_STATIC_RUNTIME=ON
-DCPPUNIT_INCLUDE_DIR=\path\to\cppunit\include
-DCPPUNIT_LIBRARIES=\path\to\cppunit\DebugDll\cppunitd_dll.lib
-DCPPUNIT_INSTALLED_VERSION=1.15.1
```
- `msbuild all_build.vcxproj /p:Configuration=Debug`
- `path %path%;\path\to\cppunit\DebugDll`
- `tests\Debug\test_runner.exe`
macOS:
* Install cppunit using a package manager, e.g. `brew install cppunit`
* Build TagLib with testing enabled:
- `cmake -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DBUILD_SHARED_LIBS=OFF`
- `make`
- `make check`

74
NEWS
View File

@@ -1,3 +1,71 @@
TagLib 1.13 (Oct 27, 2022)
==========================
* Added interface StreamTypeResolver to support streams which cannot be
fopen()'ed, e.g. network files.
* Added MP4::File::strip() to remove meta atom from MP4 file.
* Added Map::value() to look up without creating entry.
* Use property "WORK" instead of "CONTENTGROUP" for ID3v2 "TIT1" frame,
use property "WORK" for ASF "WM/ContentGroupDescription",
use property "COMPILATION" for ID3v2 "TCMP" frame.
* Build system improvements: option WITH_ZLIB, BUILD_TESTING instead of
BUILD_TESTS, GNUInstallDirs, FeatureSummary, tests with BUILD_SHARED_LIBS,
cross compilation with Buildroot, systems without HAVE_GCC_ATOMIC, Clang.
* Fixed heap-buffer-overflows when handling ASF, APE, FLAC, ID3v2, MP4, MPC
tags.
* Fixed detection of invalid file by extension when correct type can be
detected by contents.
* Fixed unnecessary creation of map entries in APE and FLAC tags if looked up
tag does not exist.
* Fixed parsing of MP4 non-full meta atoms.
* Fixed potential ID3v1 false positive in the presence of an APE tag.
* Fixed ID3v2 version handling for frames embedded in CHAP or CTOC frames.
* Fixed parsing of multiple strings with a single BOM in ID3v2.4.0.
* Fixed several smaller issues reported by clang-tidy.
TagLib 1.12 (Feb 16, 2021)
==========================
* Added support for WinRT.
* Added support for Linux on POWER.
* Added support for classical music tags of iTunes 12.5.
* Added support for file descriptor to FileStream.
* Added support for 'cmID', 'purl', 'egid' MP4 atoms.
* Added support for 'GRP1' ID3v2 frame.
* Added support for extensible WAV subformat.
* Enabled FileRef to detect file types based on the stream content.
* Dropped support for Windows 9x and NT 4.0 or older.
* Check for mandatory header objects in ASF files.
* More tolerant handling of RIFF padding, WAV files, broken MPEG streams.
* Improved calculation of Ogg, Opus, Speex, WAV, MP4 bitrates.
* Improved Windows compatibility by storing FLAC picture after comments.
* Fixed numerical genres in ID3v2.3.0 'TCON' frames.
* Fixed consistency of API removing MP4 items when empty values are set.
* Fixed consistency of API preferring COMM frames with no description.
* Fixed OOB read on invalid Ogg FLAC files (CVE-2018-11439).
* Fixed handling of empty MPEG files.
* Fixed parsing MP4 mdhd timescale.
* Fixed reading MP4 atoms with zero length.
* Fixed reading FLAC files with zero-sized seektables.
* Fixed handling of lowercase field names in Vorbis Comments.
* Fixed handling of 'rate' atoms in MP4 files.
* Fixed handling of invalid UTF-8 sequences.
* Fixed possible file corruptions when saving Ogg files.
* Fixed handling of non-audio blocks, sampling rates, DSD audio in WavPack files.
* TableOfContentsFrame::toString() improved.
* UserTextIdentificationFrame::toString() improved.
* Marked FileRef::create() deprecated.
* Marked MPEG::File::save() with boolean parameters deprecated,
provide overloads with enum parameters.
* Several smaller bug fixes and performance improvements.
TagLib 1.11.1 (Oct 24, 2016)
============================
* Fixed binary incompatible change in TagLib::String.
* Fixed reading ID3v2 CTOC frames with a lot of entries.
* Fixed seeking ByteVectorStream from the end.
TagLib 1.11 (Apr 29, 2016)
==========================
@@ -215,7 +283,7 @@ TagLib 1.6.3 (Apr 17, 2010)
* Fixed definitions of the TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF macros.
* Fixed upgrading of ID3v2.3 genre frame with ID3v1 code 0 (Blues).
* New method `int String::toInt(bool *ok)` which can return whether the
conversion to a number was successfull.
conversion to a number was successful.
* Fixed parsing of incorrectly written lengths in ID3v2 (affects mainly
compressed frames). (BUG:231075)
@@ -223,7 +291,7 @@ TagLib 1.6.2 (Apr 9, 2010)
==========================
* Read Vorbis Comments from the first FLAC metadata block, if there are
multipe ones. (BUG:211089)
multiple ones. (BUG:211089)
* Fixed a memory leak in FileRef's OGA format detection.
* Fixed compilation with the Sun Studio compiler. (BUG:215225)
* Handle WM/TrackNumber attributes with DWORD content in WMA files.
@@ -258,7 +326,7 @@ TagLib 1.6 (Sep 13, 2009)
* Added support for disabling dllimport/dllexport on Windows using the
TAGLIB_STATIC macro.
* Support for parsing the obsolete 'gnre' MP4 atom.
* New cpp macros TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF to determin if
* New cpp macros TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF to determine if
TagLib was built with MP4/ASF support.
1.6 RC1:

25
README.md Normal file
View File

@@ -0,0 +1,25 @@
# TagLib
[![Build Status](../../actions/workflows/build.yml/badge.svg)](../../actions)
### TagLib Audio Metadata Library
https://taglib.org/
TagLib is a library for reading and editing the metadata of several
popular audio formats. Currently it supports both ID3v1 and [ID3v2][]
for MP3 files, [Ogg Vorbis][] comments and ID3 tags
in [FLAC][], MPC, Speex, WavPack, TrueAudio, WAV, AIFF, MP4, APE,
and ASF files.
TagLib is distributed under the [GNU Lesser General Public License][]
(LGPL) and [Mozilla Public License][] (MPL). Essentially that means that
it may be used in proprietary applications, but if changes are made to
TagLib they must be contributed back to the project. Please review the
licenses if you are considering using TagLib in your project.
[ID3v2]: https://id3.org/
[Ogg Vorbis]: https://xiph.org/vorbis/
[FLAC]: https://xiph.org/flac/
[GNU Lesser General Public License]: https://www.gnu.org/licenses/lgpl.html
[Mozilla Public License]: https://www.mozilla.org/MPL/MPL-1.1.html

View File

@@ -21,7 +21,14 @@ set(tag_c_HDRS tag_c.h)
add_library(tag_c tag_c.cpp ${tag_c_HDRS})
target_link_libraries(tag_c tag)
set_target_properties(tag_c PROPERTIES PUBLIC_HEADER "${tag_c_HDRS}")
set_target_properties(tag_c PROPERTIES
PUBLIC_HEADER "${tag_c_HDRS}"
DEFINE_SYMBOL MAKE_TAGLIB_LIB
)
if(VISIBILITY_HIDDEN)
set_target_properties(tag_c PROPERTIES C_VISIBILITY_PRESET hidden
)
endif()
if(BUILD_FRAMEWORK)
set_target_properties(tag_c PROPERTIES FRAMEWORK TRUE)
endif()
@@ -51,18 +58,18 @@ set_target_properties(tag_c PROPERTIES
VERSION 0.0.0
SOVERSION 0
DEFINE_SYMBOL MAKE_TAGLIB_C_LIB
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
INSTALL_NAME_DIR ${CMAKE_INSTALL_LIBDIR}
)
install(TARGETS tag_c
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/taglib
)
if(NOT BUILD_FRAMEWORK)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif()

View File

@@ -69,7 +69,7 @@ namespace
{
return String(s, unicodeStrings ? String::UTF8 : String::Latin1);
}
}
} // namespace
void taglib_set_strings_unicode(BOOL unicode)
{

View File

@@ -1,12 +1,12 @@
prefix=${CMAKE_INSTALL_PREFIX}
exec_prefix=${CMAKE_INSTALL_PREFIX}
libdir=${LIB_INSTALL_DIR}
includedir=${INCLUDE_INSTALL_DIR}
libdir=${CMAKE_INSTALL_FULL_LIBDIR}
includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}
Name: TagLib C Bindings
Description: Audio meta-data library (C bindings)
Requires: taglib
Version: ${TAGLIB_LIB_VERSION_STRING}
Libs: -L${LIB_INSTALL_DIR} -ltag_c
Cflags: -I${INCLUDE_INSTALL_DIR}/taglib
Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -ltag_c
Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}/taglib

View File

@@ -33,7 +33,7 @@ ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
FIND_PATH(CPPUNIT_CFLAGS cppunit/TestRunner.h PATHS /usr/include /usr/local/include )
FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib )
# how can we find cppunit version?
MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}")
MESSAGE (STATUS "Ensure your cppunit installed version is at least ${CPPUNIT_MIN_VERSION}")
SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION})
ENDIF(CPPUNIT_CONFIG_EXECUTABLE)

View File

@@ -1,7 +1,9 @@
/* config.h. Generated by cmake from config.h.cmake */
#ifndef TAGLIB_CONFIG_H
#define TAGLIB_CONFIG_H
/* Defined if your compiler supports some byte swap functions */
#cmakedefine HAVE_BOOST_BYTESWAP 1
#cmakedefine HAVE_GCC_BYTESWAP 1
#cmakedefine HAVE_GLIBC_BYTESWAP 1
#cmakedefine HAVE_MSC_BYTESWAP 1
@@ -9,8 +11,6 @@
#cmakedefine HAVE_OPENBSD_BYTESWAP 1
/* Defined if your compiler supports some atomic operations */
#cmakedefine HAVE_STD_ATOMIC 1
#cmakedefine HAVE_BOOST_ATOMIC 1
#cmakedefine HAVE_GCC_ATOMIC 1
#cmakedefine HAVE_MAC_ATOMIC 1
#cmakedefine HAVE_WIN_ATOMIC 1
@@ -25,9 +25,10 @@
/* Defined if zlib is installed */
#cmakedefine HAVE_ZLIB 1
#cmakedefine HAVE_BOOST_ZLIB 1
/* Indicates whether debug messages are shown even in release mode */
#cmakedefine TRACE_IN_RELEASE 1
#cmakedefine TESTS_DIR "@TESTS_DIR@"
#endif

View File

@@ -1,4 +1,2 @@
</div>
</div>
</body>
</html>

View File

@@ -1,41 +1,38 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>$title ($projectname)</title>
<link href="taglib-api.css" rel="stylesheet" type="text/css">
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
</head>
<body>
<div id="container">
<table border="0" width="100%">
<tr>
<td width="1">
<img src="../taglib.png">
</td>
<td>
<div id="intro">
<table border="0" height="119" cellpadding="0" cellspacing="0" width="100%">
<tr><td valign="top"><h1>TagLib $projectnumber ($title)</h1></td></tr>
<tr>
<td valign="bottom">
<div id="links">
<a href="index.html">Home</a>
<a href="inherits.html">Class&nbsp;Hierarchy</a>
<a href="namespaces.html">Namespaces</a>
<a href="annotated.html">Classes</a>
<a href="files.html">Headers</a>
<a href="namespacemembers.html">Namespace&nbsp;Members</a>
<a href="functions.html">Class&nbsp;Members</a>
<a href="globals.html">File&nbsp;Members</a>
</div>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
<div id="text">
<div id="top">
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo" width="200px"/></td>
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">$projectname
&#160;<span id="projectnumber">$projectnumber</span>
</div>
<div id="projectbrief">$projectbrief</div>
</td>
<td style="padding-left: 0.5em;">
<div id="projectbrief">$projectbrief</div>
</td>
<td>$searchbox</td>
</tr>
</tbody>
</table>
</div>

View File

@@ -1,395 +0,0 @@
body {
font-family: sans-serif;
background: white;
color: black;
margin: 0px;
padding: 15px;
}
a:link {
font-weight: bold;
text-decoration: none;
color: gray;
}
a:visited {
font-weight: bold;
text-decoration: none;
color: gray;
}
a:hover {
color: #cccccc;
text-decoration: underline;
}
a:active {
color: #cccccc;
text-decoration: underline;
}
img {
border-style: none;
}
h1 {
font-family: sans-serif;
}
h2 {
font-family: sans-serif;
}
h3 {
font-family: sans-serif;
}
/* container */
#container {
position: absolute;
border-width: thin;
border-style: solid;
width: 95%;
}
/* intro */
#intro {
padding: 5px;
margin: 0px;
background: #cccccc;
border-width: medium;
border-style: solid;
}
#intro h1 {
margin: 5px;
padding: 5px;
}
/* links */
#links {
font-size: x-small;
vertical-align: bottom;
}
#links a {
border-width: thin;
border-style: dotted;
border-color: white;
/* margin: 0px 10px 0px 0px; */
margin: 1px;
padding: 3px;
line-height: 230%
}
#links a:hover {
color: black;
text-decoration: underline;
}
#links h3 {
outline-width: thin;
border-style: solid;
padding: 2px;
margin: 3px 0px 3px 0px;
}
/* menu */
#menu h3 {
text-align: center;
}
/* text */
#text {
margin: 0px;
padding: 5px 5px 0px 5px;
float: left;
}
#text h3 {
border-width: thin;
border-style: solid;
padding: 2px;
margin: 3px 0px 3px 0px;
}
#text li {
margin: 0px 0px 10px 0px;
}
#text ul {
margin: 5px;
padding: 0px 0px 0px 20px;
}
#leftcolumn {
float: left;
width: 300px;
margin: 0px 10px 0px 0px;
padding: 0px;
}
#rightcolumn {
float: right;
width: 210px;
margin: 0px;
padding: 0px;
}
/* vspacer */
.vspacer {
height: 10px;
}
.silver {
border-width: thin;
border-color: black;
border-style: solid;
background: #cccccc;
}
a.code {
text-decoration: none;
font-weight: normal;
color: #4444ee
}
a.codeRef {
font-weight: normal;
color: #4444ee
}
div.fragment {
width: 98%;
border: 1px solid #CCCCCC;
background-color: #f5f5f5;
padding-left: 4px;
margin: 4px;
}
div.ah {
background-color: black;
font-weight: bold; color: #ffffff;
margin-bottom: 3px;
margin-top: 3px
}
#text td {
width: auto;
}
div.memdoc {
margin-top: 0px;
margin-bottom: 20px;
padding: 10px 10px 10px 40px;
}
div.memproto {
border: thin solid black;
background-color: #f2f2ff;
width: 100%;
margin-top: 20px;
padding-top: 10px;
padding-bottom: 10px;
}
td.paramtype {
color: #602020;
}
table.memname {
font-weight: bold;
}
div.groupHeader {
margin-left: 16px;
margin-top: 12px;
margin-bottom: 6px;
font-weight: bold
}
div.groupText {
margin-left: 16px;
font-style: italic;
font-size: smaller
}
body {
background: white;
color: black;
margin-right: 20px;
margin-left: 20px;
}
td.indexkey {
background-color: #eeeeff;
font-weight: bold;
padding-right : 10px;
padding-top : 2px;
padding-left : 10px;
padding-bottom : 2px;
margin-left : 0px;
margin-right : 0px;
margin-top : 2px;
margin-bottom : 2px
}
td.indexvalue {
background-color: #eeeeff;
font-style: italic;
padding-right : 10px;
padding-top : 2px;
padding-left : 10px;
padding-bottom : 2px;
margin-left : 0px;
margin-right : 0px;
margin-top : 2px;
margin-bottom : 2px
}
tr.memlist {
background-color: #f0f0f0;
}
p.formulaDsp {
text-align: center;
}
img.formulaDsp {
}
img.formulaInl {
vertical-align: middle;
}
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
.mdTable {
border: 1px solid #868686;
background-color: #f2f2ff;
}
.mdRow {
padding: 8px 20px;
}
.mdescLeft {
font-size: smaller;
font-family: Arial, Helvetica, sans-serif;
background-color: #FAFAFA;
padding-left: 8px;
border-top: 1px none #E0E0E0;
border-right: 1px none #E0E0E0;
border-bottom: 1px none #E0E0E0;
border-left: 1px none #E0E0E0;
margin: 0px;
}
.mdescRight {
font-size: smaller;
font-family: Arial, Helvetica, sans-serif;
font-style: italic;
background-color: #FAFAFA;
padding-left: 4px;
border-top: 1px none #E0E0E0;
border-right: 1px none #E0E0E0;
border-bottom: 1px none #E0E0E0;
border-left: 1px none #E0E0E0;
margin: 0px;
padding-bottom: 0px;
padding-right: 8px;
}
.memItemLeft {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-style: solid;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-family: Geneva, Arial, Helvetica, sans-serif;
font-size: 12px;
}
.memItemRight {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-style: solid;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-family: Geneva, Arial, Helvetica, sans-serif;
font-size: 13px;
}
.search {
color: #0000ee;
font-weight: bold;
}
form.search {
margin-bottom: 0px;
margin-top: 0px;
}
input.search {
font-size: 75%;
color: #000080;
font-weight: normal;
background-color: #eeeeff;
}
td.tiny {
font-size: 75%;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

58
doc/taglib.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -5,6 +5,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v1
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2/frames
${CMAKE_CURRENT_SOURCE_DIR}/../bindings/c/
)
@@ -37,3 +38,8 @@ target_link_libraries(framelist tag)
add_executable(strip-id3v1 strip-id3v1.cpp)
target_link_libraries(strip-id3v1 tag)
install(TARGETS tagreader tagreader_c tagwriter framelist strip-id3v1
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

View File

@@ -32,6 +32,7 @@
#include <id3v2tag.h>
#include <id3v2frame.h>
#include <id3v2header.h>
#include <commentsframe.h>
#include <id3v1tag.h>
@@ -65,8 +66,15 @@ int main(int argc, char *argv[])
<< endl;
ID3v2::FrameList::ConstIterator it = id3v2tag->frameList().begin();
for(; it != id3v2tag->frameList().end(); it++)
cout << (*it)->frameID() << " - \"" << (*it)->toString() << "\"" << endl;
for(; it != id3v2tag->frameList().end(); it++) {
cout << (*it)->frameID();
if(ID3v2::CommentsFrame *comment = dynamic_cast<ID3v2::CommentsFrame *>(*it))
if(!comment->description().isEmpty())
cout << " [" << comment->description() << "]";
cout << " - \"" << (*it)->toString() << "\"" << endl;
}
}
else
cout << "file does not have a valid id3v2 tag" << endl;

View File

@@ -14,10 +14,20 @@ EOH
exit 1;
}
prefix=${CMAKE_INSTALL_PREFIX}
exec_prefix=${CMAKE_INSTALL_PREFIX}
libdir=${LIB_INSTALL_DIR}
includedir=${INCLUDE_INSTALL_DIR}
# Looks useless as it is, but could be replaced with a "pcfiledir" by Buildroot.
prefix=
exec_prefix=
if test -z "$prefix"; then
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
else
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
fi
if test -z "$exec_prefix"; then
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
else
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
fi
flags=""
@@ -29,16 +39,16 @@ while test $# -gt 0
do
case $1 in
--libs)
flags="$flags -L$libdir -ltag"
flags="$flags -L$libdir -ltag @ZLIB_LIBRARIES_FLAGS@"
;;
--cflags)
flags="$flags -I$includedir/taglib"
flags="$flags -I$includedir -I$includedir/taglib"
;;
--version)
echo ${TAGLIB_LIB_VERSION_STRING}
echo @TAGLIB_LIB_VERSION_STRING@
;;
--prefix)
echo $prefix
echo ${prefix:-@CMAKE_INSTALL_PREFIX@}
;;
*)
echo "$0: unknown option $1"

View File

@@ -27,8 +27,8 @@ goto theend
* to allow for static, shared or debug builds.
* It would be preferable if the top level CMakeLists.txt provided the library name during config. ??
:doit
if /i "%1#" == "--libs#" echo -L${LIB_INSTALL_DIR} -llibtag
if /i "%1#" == "--cflags#" echo -I${INCLUDE_INSTALL_DIR}/taglib
if /i "%1#" == "--libs#" echo -L${CMAKE_INSTALL_FULL_LIBDIR} -llibtag
if /i "%1#" == "--cflags#" echo -I${CMAKE_INSTALL_FULL_INCLUDEDIR} -I${CMAKE_INSTALL_FULL_INCLUDEDIR}/taglib
if /i "%1#" == "--version#" echo ${TAGLIB_LIB_VERSION_STRING}
if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX}

View File

@@ -1,11 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=@LIB_INSTALL_DIR@
includedir=@INCLUDE_INSTALL_DIR@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: TagLib
Description: Audio meta-data library
Requires:
Requires:
Version: @TAGLIB_LIB_VERSION_STRING@
Libs: -L${libdir} -ltag
Cflags: -I${includedir}/taglib
Libs: -L${libdir} -ltag @ZLIB_LIBRARIES_FLAGS@
Cflags: -I${includedir} -I${includedir}/taglib

View File

@@ -24,6 +24,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/s3m
${CMAKE_CURRENT_SOURCE_DIR}/it
${CMAKE_CURRENT_SOURCE_DIR}/xm
${taglib_SOURCE_DIR}/3rdparty
)
if(ZLIB_FOUND)
@@ -32,10 +33,6 @@ elseif(HAVE_ZLIB_SOURCE)
include_directories(${ZLIB_SOURCE})
endif()
if(HAVE_BOOST_BYTESWAP OR HAVE_BOOST_ATOMIC OR HAVE_BOOST_ZLIB)
include_directories(${Boost_INCLUDE_DIR})
endif()
set(tag_HDRS
tag.h
fileref.h
@@ -64,6 +61,7 @@ set(tag_HDRS
mpeg/xingheader.h
mpeg/id3v1/id3v1tag.h
mpeg/id3v1/id3v1genres.h
mpeg/id3v2/id3v2.h
mpeg/id3v2/id3v2extendedheader.h
mpeg/id3v2/id3v2frame.h
mpeg/id3v2/id3v2header.h
@@ -312,12 +310,6 @@ set(toolkit_SRCS
toolkit/tzlib.cpp
)
if(NOT WIN32)
set(unicode_SRCS
toolkit/unicode.cpp
)
endif()
if(HAVE_ZLIB_SOURCE)
set(zlib_SRCS
${ZLIB_SOURCE}/adler32.c
@@ -334,7 +326,7 @@ set(tag_LIB_SRCS
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${unicode_SRCS} ${zlib_SRCS}
${zlib_SRCS}
tag.cpp
tagunion.cpp
fileref.cpp
@@ -343,35 +335,38 @@ set(tag_LIB_SRCS
)
add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
set_property(TARGET tag PROPERTY CXX_STANDARD 98)
if(ZLIB_FOUND)
if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
target_link_libraries(tag ${ZLIB_LIBRARIES})
endif()
if(HAVE_BOOST_ATOMIC)
target_link_libraries(tag ${Boost_ATOMIC_LIBRARY})
endif()
if(HAVE_BOOST_ZLIB)
target_link_libraries(tag ${Boost_IOSTREAMS_LIBRARY} ${Boost_ZLIB_LIBRARY})
endif()
set_target_properties(tag PROPERTIES
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
INSTALL_NAME_DIR ${CMAKE_INSTALL_LIBDIR}
DEFINE_SYMBOL MAKE_TAGLIB_LIB
LINK_INTERFACE_LIBRARIES ""
PUBLIC_HEADER "${tag_HDRS}"
)
if(VISIBILITY_HIDDEN)
set_target_properties(tag PROPERTIES C_VISIBILITY_PRESET hidden)
endif()
if(BUILD_FRAMEWORK)
set_target_properties(tag PROPERTIES FRAMEWORK TRUE)
unset(INSTALL_NAME_DIR)
set_target_properties(tag PROPERTIES
FRAMEWORK TRUE
MACOSX_RPATH 1
VERSION "A"
SOVERSION "A"
)
endif()
install(TARGETS tag
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/taglib
)

View File

@@ -49,8 +49,8 @@ APE Tag Version 2.000 (with header, recommended):
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
is not required, but is strongly recommended. It would be desirable for the
items 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

View File

@@ -83,6 +83,18 @@ public:
Properties *properties;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool APE::File::isSupported(IOStream *stream)
{
// An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede.
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
return (buffer.find("MAC ") >= 0);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

View File

@@ -211,6 +211,15 @@ namespace TagLib {
*/
bool hasID3v1Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as an APE
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);

View File

@@ -135,8 +135,7 @@ unsigned int APE::Footer::completeTagSize() const
{
if(d->headerPresent)
return d->tagSize + size();
else
return d->tagSize;
return d->tagSize;
}
void APE::Footer::setTagSize(unsigned int s)
@@ -158,8 +157,7 @@ ByteVector APE::Footer::renderHeader() const
{
if(!d->headerPresent)
return ByteVector();
else
return render(true);
return render(true);
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -219,8 +219,7 @@ String APE::Item::toString() const
{
if(d->type == Text && !isEmpty())
return d->text.front();
else
return String();
return String();
}
bool APE::Item::isEmpty() const
@@ -229,9 +228,7 @@ bool APE::Item::isEmpty() const
case Text:
if(d->text.isEmpty())
return true;
if(d->text.size() == 1 && d->text.front().isEmpty())
return true;
return false;
return d->text.size() == 1 && d->text.front().isEmpty();
case Binary:
case Locator:
return d->value.isEmpty();

View File

@@ -53,9 +53,9 @@ namespace TagLib {
* Create an instance of APE::Properties with the data read from the
* APE::File \a file.
*
* \deprecated
* \deprecated Use Properties(File *, long, ReadStyle).
*/
Properties(File *file, ReadStyle style = Average);
TAGLIB_DEPRECATED Properties(File *file, ReadStyle style = Average);
/*!
* Create an instance of APE::Properties with the data read from the
@@ -74,9 +74,9 @@ namespace TagLib {
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
* \deprecated Use lengthInSeconds().
*/
virtual int length() const;
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to

View File

@@ -47,29 +47,30 @@ using namespace APE;
namespace
{
bool isKeyValid(const char *key, size_t length)
const unsigned int MinKeyLength = 2;
const unsigned int MaxKeyLength = 255;
bool isKeyValid(const ByteVector &key)
{
const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };
if(length < 2 || length > 255)
return false;
// only allow printable ASCII including space (32..126)
for(const char *p = key; p < key + length; ++p) {
const int c = static_cast<unsigned char>(*p);
for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) {
const int c = static_cast<unsigned char>(*it);
if(c < 32 || c > 126)
return false;
}
const String upperKey = String(key).upper();
for(size_t i = 0; invalidKeys[i] != 0; ++i) {
if(Utils::equalsIgnoreCase(key, invalidKeys[i]))
if(upperKey == invalidKeys[i])
return false;
}
return true;
}
}
} // namespace
class APE::Tag::TagPrivate
{
@@ -90,13 +91,11 @@ public:
////////////////////////////////////////////////////////////////////////////////
APE::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
}
APE::Tag::Tag(TagLib::File *file, long footerLocation) :
TagLib::Tag(),
d(new TagPrivate())
{
d->file = file;
@@ -117,51 +116,44 @@ ByteVector APE::Tag::fileIdentifier()
String APE::Tag::title() const
{
if(d->itemListMap["TITLE"].isEmpty())
return String();
return d->itemListMap["TITLE"].values().toString();
Item value = d->itemListMap.value("TITLE");
return value.isEmpty() ? String() : value.values().toString();
}
String APE::Tag::artist() const
{
if(d->itemListMap["ARTIST"].isEmpty())
return String();
return d->itemListMap["ARTIST"].values().toString();
Item value = d->itemListMap.value("ARTIST");
return value.isEmpty() ? String() : value.values().toString();
}
String APE::Tag::album() const
{
if(d->itemListMap["ALBUM"].isEmpty())
return String();
return d->itemListMap["ALBUM"].values().toString();
Item value = d->itemListMap.value("ALBUM");
return value.isEmpty() ? String() : value.values().toString();
}
String APE::Tag::comment() const
{
if(d->itemListMap["COMMENT"].isEmpty())
return String();
return d->itemListMap["COMMENT"].values().toString();
Item value = d->itemListMap.value("COMMENT");
return value.isEmpty() ? String() : value.values().toString();
}
String APE::Tag::genre() const
{
if(d->itemListMap["GENRE"].isEmpty())
return String();
return d->itemListMap["GENRE"].values().toString();
Item value = d->itemListMap.value("GENRE");
return value.isEmpty() ? String() : value.values().toString();
}
unsigned int APE::Tag::year() const
{
if(d->itemListMap["YEAR"].isEmpty())
return 0;
return d->itemListMap["YEAR"].toString().toInt();
Item value = d->itemListMap.value("YEAR");
return value.isEmpty() ? 0 : value.toString().toInt();
}
unsigned int APE::Tag::track() const
{
if(d->itemListMap["TRACK"].isEmpty())
return 0;
return d->itemListMap["TRACK"].toString().toInt();
Item value = d->itemListMap.value("TRACK");
return value.isEmpty() ? 0 : value.toString().toInt();
}
void APE::Tag::setTitle(const String &s)
@@ -191,7 +183,7 @@ void APE::Tag::setGenre(const String &s)
void APE::Tag::setYear(unsigned int i)
{
if(i <= 0)
if(i == 0)
removeItem("YEAR");
else
addValue("YEAR", String::number(i), true);
@@ -199,7 +191,7 @@ void APE::Tag::setYear(unsigned int i)
void APE::Tag::setTrack(unsigned int i)
{
if(i <= 0)
if(i == 0)
removeItem("TRACK");
else
addValue("TRACK", String::number(i), true);
@@ -209,14 +201,18 @@ namespace
{
// conversions of tag keys between what we use in PropertyMap and what's usual
// for APE tags
// usual, APE
const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
{"DATE", "YEAR" },
{"ALBUMARTIST", "ALBUM ARTIST"},
{"DISCNUMBER", "DISC" },
{"REMIXER", "MIXARTIST" }};
// usual, APE
const std::pair<const char *, const char *> keyConversions[] = {
std::make_pair("TRACKNUMBER", "TRACK"),
std::make_pair("DATE", "YEAR"),
std::make_pair("ALBUMARTIST", "ALBUM ARTIST"),
std::make_pair("DISCNUMBER", "DISC"),
std::make_pair("REMIXER", "MIXARTIST"),
std::make_pair("RELEASESTATUS", "MUSICBRAINZ_ALBUMSTATUS"),
std::make_pair("RELEASETYPE", "MUSICBRAINZ_ALBUMTYPE"),
};
const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]);
}
} // namespace
PropertyMap APE::Tag::properties() const
{
@@ -232,8 +228,8 @@ PropertyMap APE::Tag::properties() const
else {
// Some tags need to be handled specially
for(size_t i = 0; i < keyConversionsSize; ++i) {
if(tagName == keyConversions[i][1])
tagName = keyConversions[i][0];
if(tagName == keyConversions[i].second)
tagName = keyConversions[i].first;
}
properties[tagName].append(it->second.toStringList());
}
@@ -254,9 +250,9 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
// see comment in properties()
for(size_t i = 0; i < keyConversionsSize; ++i)
if(properties.contains(keyConversions[i][0])) {
properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]);
properties.erase(keyConversions[i][0]);
if(properties.contains(keyConversions[i].first)) {
properties.insert(keyConversions[i].second, properties[keyConversions[i].first]);
properties.erase(keyConversions[i].first);
}
// first check if tags need to be removed completely
@@ -296,11 +292,10 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
bool APE::Tag::checkKey(const String &key)
{
if(!key.isLatin1())
if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
return false;
const std::string data = key.to8Bit(false);
return isKeyValid(data.c_str(), data.size());
return isKeyValid(key.data(String::UTF8));
}
APE::Footer *APE::Tag::footer() const
@@ -417,9 +412,17 @@ void APE::Tag::parse(const ByteVector &data)
}
const unsigned int keyLength = nullPos - pos - 8;
const unsigned int valLegnth = data.toUInt(pos, false);
const unsigned int valLength = data.toUInt(pos, false);
if(isKeyValid(&data[pos + 8], keyLength)){
if(valLength >= data.size() || pos > data.size() - valLength) {
debug("APE::Tag::parse() - Invalid val length. Stopped parsing.");
return;
}
if(keyLength >= MinKeyLength
&& keyLength <= MaxKeyLength
&& isKeyValid(data.mid(pos + 8, keyLength)))
{
APE::Item item;
item.parse(data.mid(pos));
@@ -429,6 +432,6 @@ void APE::Tag::parse(const ByteVector &data)
debug("APE::Tag::parse() - Skipped an item due to an invalid key.");
}
pos += keyLength + valLegnth + 9;
pos += keyLength + valLength + 9;
}
}

View File

@@ -36,20 +36,16 @@ using namespace TagLib;
class ASF::Attribute::AttributePrivate : public RefCounter
{
public:
AttributePrivate()
: pictureValue(ASF::Picture::fromInvalid()),
stream(0),
language(0) {}
AttributePrivate() :
pictureValue(ASF::Picture::fromInvalid()),
numericValue(0),
stream(0),
language(0) {}
AttributeTypes type;
String stringValue;
ByteVector byteVectorValue;
ASF::Picture pictureValue;
union {
unsigned int intValue;
unsigned short shortValue;
unsigned long long longLongValue;
bool boolValue;
};
unsigned long long numericValue;
int stream;
int language;
};
@@ -95,28 +91,28 @@ ASF::Attribute::Attribute(unsigned int value) :
d(new AttributePrivate())
{
d->type = DWordType;
d->intValue = value;
d->numericValue = value;
}
ASF::Attribute::Attribute(unsigned long long value) :
d(new AttributePrivate())
{
d->type = QWordType;
d->longLongValue = value;
d->numericValue = value;
}
ASF::Attribute::Attribute(unsigned short value) :
d(new AttributePrivate())
{
d->type = WordType;
d->shortValue = value;
d->numericValue = value;
}
ASF::Attribute::Attribute(bool value) :
d(new AttributePrivate())
{
d->type = BoolType;
d->boolValue = value;
d->numericValue = value;
}
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
@@ -157,22 +153,22 @@ ByteVector ASF::Attribute::toByteVector() const
unsigned short ASF::Attribute::toBool() const
{
return d->shortValue;
return d->numericValue ? 1 : 0;
}
unsigned short ASF::Attribute::toUShort() const
{
return d->shortValue;
return static_cast<unsigned short>(d->numericValue);
}
unsigned int ASF::Attribute::toUInt() const
{
return d->intValue;
return static_cast<unsigned int>(d->numericValue);
}
unsigned long long ASF::Attribute::toULongLong() const
{
return d->longLongValue;
return static_cast<unsigned long long>(d->numericValue);
}
ASF::Picture ASF::Attribute::toPicture() const
@@ -212,24 +208,24 @@ String ASF::Attribute::parse(ASF::File &f, int kind)
switch(d->type) {
case WordType:
d->shortValue = readWORD(&f);
d->numericValue = readWORD(&f);
break;
case BoolType:
if(kind == 0) {
d->boolValue = (readDWORD(&f) == 1);
d->numericValue = (readDWORD(&f) != 0);
}
else {
d->boolValue = (readWORD(&f) == 1);
d->numericValue = (readWORD(&f) != 0);
}
break;
case DWordType:
d->intValue = readDWORD(&f);
d->numericValue = readDWORD(&f);
break;
case QWordType:
d->longLongValue = readQWORD(&f);
d->numericValue = readQWORD(&f);
break;
case UnicodeType:
@@ -280,24 +276,24 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
switch (d->type) {
case WordType:
data.append(ByteVector::fromShort(d->shortValue, false));
data.append(ByteVector::fromShort(toUShort(), false));
break;
case BoolType:
if(kind == 0) {
data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false));
data.append(ByteVector::fromUInt(toBool(), false));
}
else {
data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false));
data.append(ByteVector::fromShort(toBool(), false));
}
break;
case DWordType:
data.append(ByteVector::fromUInt(d->intValue, false));
data.append(ByteVector::fromUInt(toUInt(), false));
break;
case QWordType:
data.append(ByteVector::fromLongLong(d->longLongValue, false));
data.append(ByteVector::fromLongLong(toULongLong(), false));
break;
case UnicodeType:
@@ -316,7 +312,7 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
if(kind == 0) {
data = renderString(name, true) +
ByteVector::fromShort((int)d->type, false) +
ByteVector::fromShort(static_cast<int>(d->type), false) +
ByteVector::fromShort(data.size(), false) +
data;
}
@@ -325,7 +321,7 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
ByteVector::fromShort(d->stream, false) +
ByteVector::fromShort(nameData.size(), false) +
ByteVector::fromShort((int)d->type, false) +
ByteVector::fromShort(static_cast<int>(d->type), false) +
ByteVector::fromUInt(data.size(), false) +
nameData +
data;

View File

@@ -113,7 +113,7 @@ namespace TagLib
/*!
* Copies the contents of \a other into this item.
*/
ASF::Attribute &operator=(const Attribute &other);
Attribute &operator=(const Attribute &other);
/*!
* Exchanges the content of the Attribute by the content of \a other.

View File

@@ -27,6 +27,7 @@
#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tstring.h>
#include <tagutils.h>
#include "asffile.h"
#include "asftag.h"
@@ -96,7 +97,7 @@ namespace
const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
}
} // namespace
class ASF::File::FilePrivate::BaseObject
{
@@ -193,7 +194,7 @@ private:
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
{
data.clear();
if(size > 24 && size <= (unsigned int)(file->length()))
if(size > 24 && size <= static_cast<unsigned int>(file->length()))
data = file->readBlock(size - 24);
else
data = ByteVector();
@@ -258,7 +259,6 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->contentDescriptionObject = this;
const int titleLength = readWORD(file);
const int artistLength = readWORD(file);
const int copyrightLength = readWORD(file);
@@ -299,7 +299,6 @@ ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() cons
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->extendedContentDescriptionObject = this;
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
@@ -323,7 +322,6 @@ ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->metadataObject = this;
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
@@ -347,7 +345,6 @@ ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->metadataLibraryObject = this;
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
@@ -376,7 +373,6 @@ ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->headerExtensionObject = this;
file->seek(18, File::Current);
long long dataSize = readDWORD(file);
long long dataPos = 0;
@@ -388,21 +384,23 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig
}
bool ok;
long long size = readQWORD(file, &ok);
if(!ok) {
if(!ok || size < 0 || size > dataSize - dataPos) {
file->setValid(false);
break;
}
BaseObject *obj;
if(guid == metadataGuid) {
obj = new MetadataObject();
file->d->metadataObject = new MetadataObject();
obj = file->d->metadataObject;
}
else if(guid == metadataLibraryGuid) {
obj = new MetadataLibraryObject();
file->d->metadataLibraryObject = new MetadataLibraryObject();
obj = file->d->metadataLibraryObject;
}
else {
obj = new UnknownObject(guid);
}
obj->parse(file, (unsigned int)size);
obj->parse(file, static_cast<unsigned int>(size));
objects.append(obj);
dataPos += size;
}
@@ -473,6 +471,18 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in
}
}
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool ASF::File::isSupported(IOStream *stream)
{
// An ASF file has to start with the designated GUID.
const ByteVector id = Utils::readHeader(stream, 16, false);
return (id == headerGuid);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
@@ -616,9 +626,8 @@ void ASF::File::read()
if(!isValid())
return;
ByteVector guid = readBlock(16);
if(guid != headerGuid) {
debug("ASF: Not an ASF file.");
if(readBlock(16) != headerGuid) {
debug("ASF::File::read(): Not an ASF file.");
setValid(false);
return;
}
@@ -639,32 +648,39 @@ void ASF::File::read()
}
seek(2, Current);
FilePrivate::FilePropertiesObject *filePropertiesObject = 0;
FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0;
for(int i = 0; i < numObjects; i++) {
guid = readBlock(16);
const ByteVector guid = readBlock(16);
if(guid.size() != 16) {
setValid(false);
break;
}
long size = (long)readQWORD(this, &ok);
long size = static_cast<long>(readQWORD(this, &ok));
if(!ok) {
setValid(false);
break;
}
FilePrivate::BaseObject *obj;
if(guid == filePropertiesGuid) {
obj = new FilePrivate::FilePropertiesObject();
filePropertiesObject = new FilePrivate::FilePropertiesObject();
obj = filePropertiesObject;
}
else if(guid == streamPropertiesGuid) {
obj = new FilePrivate::StreamPropertiesObject();
streamPropertiesObject = new FilePrivate::StreamPropertiesObject();
obj = streamPropertiesObject;
}
else if(guid == contentDescriptionGuid) {
obj = new FilePrivate::ContentDescriptionObject();
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
obj = d->contentDescriptionObject;
}
else if(guid == extendedContentDescriptionGuid) {
obj = new FilePrivate::ExtendedContentDescriptionObject();
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
obj = d->extendedContentDescriptionObject;
}
else if(guid == headerExtensionGuid) {
obj = new FilePrivate::HeaderExtensionObject();
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
obj = d->headerExtensionObject;
}
else if(guid == codecListGuid) {
obj = new FilePrivate::CodecListObject();
@@ -680,4 +696,10 @@ void ASF::File::read()
obj->parse(this, size);
d->objects.append(obj);
}
if(!filePropertiesObject || !streamPropertiesObject) {
debug("ASF::File::read(): Missing mandatory header objects.");
setValid(false);
return;
}
}

View File

@@ -115,6 +115,15 @@ namespace TagLib {
*/
virtual bool save();
/*!
* Returns whether or not the given \a stream can be opened as an ASF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
void read();

View File

@@ -137,7 +137,7 @@ ByteVector ASF::Picture::render() const
return ByteVector();
return
ByteVector((char)d->type) +
ByteVector(static_cast<char>(d->type)) +
ByteVector::fromUInt(d->picture.size(), false) +
renderString(d->mimeType) +
renderString(d->description) +
@@ -150,7 +150,7 @@ void ASF::Picture::parse(const ByteVector& bytes)
if(bytes.size() < 9)
return;
int pos = 0;
d->type = (Type)bytes[0]; ++pos;
d->type = static_cast<Type>(bytes[0]); ++pos;
const unsigned int dataLen = bytes.toUInt(pos, false); pos+=4;
const ByteVector nullStringTerminator(2, 0);

View File

@@ -86,9 +86,9 @@ namespace TagLib {
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
* \deprecated Use lengthInSeconds().
*/
virtual int length() const;
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to

View File

@@ -39,10 +39,9 @@ public:
AttributeListMap attributeListMap;
};
ASF::Tag::Tag()
: TagLib::Tag()
ASF::Tag::Tag() :
d(new TagPrivate())
{
d = new TagPrivate;
}
ASF::Tag::~Tag()
@@ -95,8 +94,7 @@ unsigned int ASF::Tag::track() const
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
if(attr.type() == ASF::Attribute::DWordType)
return attr.toUInt();
else
return attr.toString().toInt();
return attr.toString().toInt();
}
if(d->attributeListMap.contains("WM/Track"))
return d->attributeListMap["WM/Track"][0].toUInt();
@@ -212,59 +210,65 @@ bool ASF::Tag::isEmpty() const
namespace
{
const char *keyTranslation[][2] = {
{ "WM/AlbumTitle", "ALBUM" },
{ "WM/AlbumArtist", "ALBUMARTIST" },
{ "WM/Composer", "COMPOSER" },
{ "WM/Writer", "WRITER" },
{ "WM/Conductor", "CONDUCTOR" },
{ "WM/ModifiedBy", "REMIXER" },
{ "WM/Year", "DATE" },
{ "WM/OriginalReleaseYear", "ORIGINALDATE" },
{ "WM/Producer", "PRODUCER" },
{ "WM/ContentGroupDescription", "GROUPING" },
{ "WM/SubTitle", "SUBTITLE" },
{ "WM/SetSubTitle", "DISCSUBTITLE" },
{ "WM/TrackNumber", "TRACKNUMBER" },
{ "WM/PartOfSet", "DISCNUMBER" },
{ "WM/Genre", "GENRE" },
{ "WM/BeatsPerMinute", "BPM" },
{ "WM/Mood", "MOOD" },
{ "WM/ISRC", "ISRC" },
{ "WM/Lyrics", "LYRICS" },
{ "WM/Media", "MEDIA" },
{ "WM/Publisher", "LABEL" },
{ "WM/CatalogNo", "CATALOGNUMBER" },
{ "WM/Barcode", "BARCODE" },
{ "WM/EncodedBy", "ENCODEDBY" },
{ "WM/AlbumSortOrder", "ALBUMSORT" },
{ "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
{ "WM/ArtistSortOrder", "ARTISTSORT" },
{ "WM/TitleSortOrder", "TITLESORT" },
{ "WM/Script", "SCRIPT" },
{ "WM/Language", "LANGUAGE" },
{ "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
{ "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
{ "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
{ "MusicIP/PUID", "MUSICIP_PUID" },
{ "Acoustid/Id", "ACOUSTID_ID" },
{ "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
const std::pair<const char *, const char *> keyTranslation[] = {
std::make_pair("WM/AlbumTitle", "ALBUM"),
std::make_pair("WM/AlbumArtist", "ALBUMARTIST"),
std::make_pair("WM/Composer", "COMPOSER"),
std::make_pair("WM/Writer", "LYRICIST"),
std::make_pair("WM/Conductor", "CONDUCTOR"),
std::make_pair("WM/ModifiedBy", "REMIXER"),
std::make_pair("WM/Year", "DATE"),
std::make_pair("WM/OriginalReleaseYear", "ORIGINALDATE"),
std::make_pair("WM/Producer", "PRODUCER"),
std::make_pair("WM/ContentGroupDescription", "WORK"),
std::make_pair("WM/SubTitle", "SUBTITLE"),
std::make_pair("WM/SetSubTitle", "DISCSUBTITLE"),
std::make_pair("WM/TrackNumber", "TRACKNUMBER"),
std::make_pair("WM/PartOfSet", "DISCNUMBER"),
std::make_pair("WM/Genre", "GENRE"),
std::make_pair("WM/BeatsPerMinute", "BPM"),
std::make_pair("WM/Mood", "MOOD"),
std::make_pair("WM/ISRC", "ISRC"),
std::make_pair("WM/Lyrics", "LYRICS"),
std::make_pair("WM/Media", "MEDIA"),
std::make_pair("WM/Publisher", "LABEL"),
std::make_pair("WM/CatalogNo", "CATALOGNUMBER"),
std::make_pair("WM/Barcode", "BARCODE"),
std::make_pair("WM/EncodedBy", "ENCODEDBY"),
std::make_pair("WM/AlbumSortOrder", "ALBUMSORT"),
std::make_pair("WM/AlbumArtistSortOrder", "ALBUMARTISTSORT"),
std::make_pair("WM/ArtistSortOrder", "ARTISTSORT"),
std::make_pair("WM/TitleSortOrder", "TITLESORT"),
std::make_pair("WM/Script", "SCRIPT"),
std::make_pair("WM/Language", "LANGUAGE"),
std::make_pair("WM/ARTISTS", "ARTISTS"),
std::make_pair("ASIN", "ASIN"),
std::make_pair("MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID"),
std::make_pair("MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID"),
std::make_pair("MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID"),
std::make_pair("MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID"),
std::make_pair("MusicBrainz/Album Release Country", "RELEASECOUNTRY"),
std::make_pair("MusicBrainz/Album Status", "RELEASESTATUS"),
std::make_pair("MusicBrainz/Album Type", "RELEASETYPE"),
std::make_pair("MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID"),
std::make_pair("MusicBrainz/Release Track Id", "MUSICBRAINZ_RELEASETRACKID"),
std::make_pair("MusicBrainz/Work Id", "MUSICBRAINZ_WORKID"),
std::make_pair("MusicIP/PUID", "MUSICIP_PUID"),
std::make_pair("Acoustid/Id", "ACOUSTID_ID"),
std::make_pair("Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT"),
};
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
String translateKey(const String &key)
{
for(size_t i = 0; i < keyTranslationSize; ++i) {
if(key == keyTranslation[i][0])
return keyTranslation[i][1];
if(key == keyTranslation[i].first)
return keyTranslation[i].second;
}
return String();
}
}
} // namespace
PropertyMap ASF::Tag::properties() const
{
@@ -318,9 +322,8 @@ PropertyMap ASF::Tag::setProperties(const PropertyMap &props)
{
static Map<String, String> reverseKeyMap;
if(reverseKeyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
for(int i = 0; i < numKeys; i++) {
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
for(size_t i = 0; i < keyTranslationSize; i++) {
reverseKeyMap[keyTranslation[i].second] = keyTranslation[i].first;
}
}

View File

@@ -152,7 +152,8 @@ namespace TagLib {
virtual bool isEmpty() const;
/*!
* \deprecated
* \deprecated Use attributeListMap() const, contains(), removeItem(),
* attribute(), setAttribute(), addAttribute().
*/
AttributeListMap &attributeListMap();
@@ -160,6 +161,7 @@ namespace TagLib {
* Returns a reference to the item list map. This is an AttributeListMap of
* all of the items in the tag.
*/
// BIC: return by value
const AttributeListMap &attributeListMap() const;
/*!

View File

@@ -43,6 +43,38 @@
using namespace TagLib;
// This macro is a workaround for the fact that we can't add virtual functions.
// Should be true virtual functions in taglib2.
#define VIRTUAL_FUNCTION_WORKAROUND(function_name, default_value) \
if(dynamic_cast<const APE::Properties*>(this)) \
return dynamic_cast<const APE::Properties*>(this)->function_name(); \
if(dynamic_cast<const ASF::Properties*>(this)) \
return dynamic_cast<const ASF::Properties*>(this)->function_name(); \
if(dynamic_cast<const FLAC::Properties*>(this)) \
return dynamic_cast<const FLAC::Properties*>(this)->function_name(); \
if(dynamic_cast<const MP4::Properties*>(this)) \
return dynamic_cast<const MP4::Properties*>(this)->function_name(); \
if(dynamic_cast<const MPC::Properties*>(this)) \
return dynamic_cast<const MPC::Properties*>(this)->function_name(); \
if(dynamic_cast<const MPEG::Properties*>(this)) \
return dynamic_cast<const MPEG::Properties*>(this)->function_name(); \
if(dynamic_cast<const Ogg::Opus::Properties*>(this)) \
return dynamic_cast<const Ogg::Opus::Properties*>(this)->function_name(); \
if(dynamic_cast<const Ogg::Speex::Properties*>(this)) \
return dynamic_cast<const Ogg::Speex::Properties*>(this)->function_name(); \
if(dynamic_cast<const TrueAudio::Properties*>(this)) \
return dynamic_cast<const TrueAudio::Properties*>(this)->function_name(); \
if(dynamic_cast<const RIFF::AIFF::Properties*>(this)) \
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->function_name(); \
if(dynamic_cast<const RIFF::WAV::Properties*>(this)) \
return dynamic_cast<const RIFF::WAV::Properties*>(this)->function_name(); \
if(dynamic_cast<const Vorbis::Properties*>(this)) \
return dynamic_cast<const Vorbis::Properties*>(this)->function_name(); \
if(dynamic_cast<const WavPack::Properties*>(this)) \
return dynamic_cast<const WavPack::Properties*>(this)->function_name(); \
return (default_value);
class AudioProperties::AudioPropertiesPrivate
{
@@ -59,98 +91,12 @@ AudioProperties::~AudioProperties()
int AudioProperties::lengthInSeconds() const
{
// This is an ugly workaround but we can't add a virtual function.
// Should be virtual in taglib2.
if(dynamic_cast<const APE::Properties*>(this))
return dynamic_cast<const APE::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const ASF::Properties*>(this))
return dynamic_cast<const ASF::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const FLAC::Properties*>(this))
return dynamic_cast<const FLAC::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MP4::Properties*>(this))
return dynamic_cast<const MP4::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MPC::Properties*>(this))
return dynamic_cast<const MPC::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MPEG::Properties*>(this))
return dynamic_cast<const MPEG::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Ogg::Opus::Properties*>(this))
return dynamic_cast<const Ogg::Opus::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Ogg::Speex::Properties*>(this))
return dynamic_cast<const Ogg::Speex::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const TrueAudio::Properties*>(this))
return dynamic_cast<const TrueAudio::Properties*>(this)->lengthInSeconds();
else if (dynamic_cast<const RIFF::AIFF::Properties*>(this))
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const RIFF::WAV::Properties*>(this))
return dynamic_cast<const RIFF::WAV::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Vorbis::Properties*>(this))
return dynamic_cast<const Vorbis::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const WavPack::Properties*>(this))
return dynamic_cast<const WavPack::Properties*>(this)->lengthInSeconds();
else
return 0;
VIRTUAL_FUNCTION_WORKAROUND(lengthInSeconds, 0)
}
int AudioProperties::lengthInMilliseconds() const
{
// This is an ugly workaround but we can't add a virtual function.
// Should be virtual in taglib2.
if(dynamic_cast<const APE::Properties*>(this))
return dynamic_cast<const APE::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const ASF::Properties*>(this))
return dynamic_cast<const ASF::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const FLAC::Properties*>(this))
return dynamic_cast<const FLAC::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const MP4::Properties*>(this))
return dynamic_cast<const MP4::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const MPC::Properties*>(this))
return dynamic_cast<const MPC::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const MPEG::Properties*>(this))
return dynamic_cast<const MPEG::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const Ogg::Opus::Properties*>(this))
return dynamic_cast<const Ogg::Opus::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const Ogg::Speex::Properties*>(this))
return dynamic_cast<const Ogg::Speex::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const TrueAudio::Properties*>(this))
return dynamic_cast<const TrueAudio::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const RIFF::AIFF::Properties*>(this))
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const RIFF::WAV::Properties*>(this))
return dynamic_cast<const RIFF::WAV::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const Vorbis::Properties*>(this))
return dynamic_cast<const Vorbis::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const WavPack::Properties*>(this))
return dynamic_cast<const WavPack::Properties*>(this)->lengthInMilliseconds();
else
return 0;
VIRTUAL_FUNCTION_WORKAROUND(lengthInMilliseconds, 0)
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -27,7 +27,10 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <cstring>
#include <tfile.h>
#include <tfilestream.h>
#include <tstring.h>
#include <tdebug.h>
#include <trefcounter.h>
@@ -59,49 +62,21 @@ namespace
typedef List<const FileRef::FileTypeResolver *> ResolverList;
ResolverList fileTypeResolvers;
// Templatized internal functions. T should be String or IOStream*.
// Detect the file type by user-defined resolvers.
template <typename T>
FileName toFileName(T arg)
{
debug("FileRef::toFileName<T>(): This version should never be called.");
return FileName(L"");
}
template <>
FileName toFileName<IOStream *>(IOStream *arg)
{
return arg->name();
}
template <>
FileName toFileName<FileName>(FileName arg)
{
return arg;
}
template <typename T>
File *resolveFileType(T arg, bool readProperties,
AudioProperties::ReadStyle style)
{
debug("FileRef::resolveFileType<T>(): This version should never be called.");
return 0;
}
template <>
File *resolveFileType<IOStream *>(IOStream *arg, bool readProperties,
AudioProperties::ReadStyle style)
{
return 0;
}
template <>
File *resolveFileType<FileName>(FileName arg, bool readProperties,
AudioProperties::ReadStyle style)
File *detectByResolvers(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
#ifdef _WIN32
if(::strlen(fileName) == 0 && ::wcslen(fileName) == 0)
return 0;
#else
if(::strlen(fileName) == 0)
return 0;
#endif
ResolverList::ConstIterator it = fileTypeResolvers.begin();
for(; it != fileTypeResolvers.end(); ++it) {
File *file = (*it)->createFile(arg, readProperties, style);
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
if(file)
return file;
}
@@ -109,18 +84,31 @@ namespace
return 0;
}
template <typename T>
File* createInternal(T arg, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
File *detectByResolvers(IOStream* stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
File *file = resolveFileType(arg, readAudioProperties, audioPropertiesStyle);
if(file)
return file;
for(ResolverList::ConstIterator it = fileTypeResolvers.begin();
it != fileTypeResolvers.end(); ++it) {
if(const FileRef::StreamTypeResolver *streamResolver =
dynamic_cast<const FileRef::StreamTypeResolver*>(*it)) {
if(File *file = streamResolver->createFileFromStream(
stream, readAudioProperties, audioPropertiesStyle))
return file;
}
}
return 0;
}
// Detect the file type based on the file extension.
File* detectByExtension(IOStream *stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
#ifdef _WIN32
const String s = toFileName(arg).toString();
const String s = stream->name().toString();
#else
const String s(toFileName(arg));
const String s(stream->name());
#endif
String ext;
@@ -135,66 +123,191 @@ namespace
if(ext.isEmpty())
return 0;
// .oga can be any audio in the Ogg container. So leave it to content-based detection.
File *file = 0;
if(ext == "MP3")
return new MPEG::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "OGG")
return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "OGA") {
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
File *file = new Ogg::FLAC::File(arg, readAudioProperties, audioPropertiesStyle);
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
else if(ext == "OGG")
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "FLAC")
file = new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
else if(ext == "MPC")
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "WV")
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "SPX")
file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "OPUS")
file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "TTA")
file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "WMA" || ext == "ASF")
file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "WAV")
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "APE")
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
// module, nst and wow are possible but uncommon extensions
else if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
file = new Mod::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "S3M")
file = new S3M::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "IT")
file = new IT::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "XM")
file = new XM::File(stream, readAudioProperties, audioPropertiesStyle);
// if file is not valid, leave it to content-based detection.
if(file) {
if(file->isValid())
return file;
delete file;
return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle);
}
if(ext == "FLAC")
return new FLAC::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "MPC")
return new MPC::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "WV")
return new WavPack::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "SPX")
return new Ogg::Speex::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "OPUS")
return new Ogg::Opus::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "TTA")
return new TrueAudio::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
return new MP4::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
return new RIFF::AIFF::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "APE")
return new APE::File(arg, readAudioProperties, audioPropertiesStyle);
// module, nst and wow are possible but uncommon extensions
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
return new Mod::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "S3M")
return new S3M::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "IT")
return new IT::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(arg, readAudioProperties, audioPropertiesStyle);
return 0;
}
}
// Detect the file type based on the actual content of the stream.
File *detectByContent(IOStream *stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
File *file = 0;
if(MPEG::File::isSupported(stream))
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
else if(Ogg::Vorbis::File::isSupported(stream))
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::FLAC::File::isSupported(stream))
file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(FLAC::File::isSupported(stream))
file = new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
else if(MPC::File::isSupported(stream))
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(WavPack::File::isSupported(stream))
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::Speex::File::isSupported(stream))
file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::Opus::File::isSupported(stream))
file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
else if(TrueAudio::File::isSupported(stream))
file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
else if(MP4::File::isSupported(stream))
file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ASF::File::isSupported(stream))
file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(RIFF::AIFF::File::isSupported(stream))
file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(RIFF::WAV::File::isSupported(stream))
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
// isSupported() only does a quick check, so double check the file here.
if(file) {
if(file->isValid())
return file;
delete file;
}
return 0;
}
// Internal function that supports FileRef::create().
// This looks redundant, but necessary in order not to change the previous
// behavior of FileRef::create().
File* createInternal(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
if(file)
return file;
#ifdef _WIN32
const String s = fileName.toString();
#else
const String s(fileName);
#endif
String ext;
const int pos = s.rfind(".");
if(pos != -1)
ext = s.substr(pos + 1).upper();
if(ext.isEmpty())
return 0;
if(ext == "MP3")
return new MPEG::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "OGG")
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OGA") {
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
if(file->isValid())
return file;
delete file;
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
}
if(ext == "FLAC")
return new FLAC::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "MPC")
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WV")
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "SPX")
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OPUS")
return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "TTA")
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "APE")
return new APE::File(fileName, readAudioProperties, audioPropertiesStyle);
// module, nst and wow are possible but uncommon extensions
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "S3M")
return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "IT")
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
return 0;
}
} // namespace
class FileRef::FileRefPrivate : public RefCounter
{
public:
FileRefPrivate(File *f) :
RefCounter(),
file(f) {}
FileRefPrivate() :
file(0),
stream(0) {}
~FileRefPrivate() {
delete file;
delete stream;
}
File *file;
File *file;
IOStream *stream;
};
////////////////////////////////////////////////////////////////////////////////
@@ -202,24 +315,27 @@ public:
////////////////////////////////////////////////////////////////////////////////
FileRef::FileRef() :
d(new FileRefPrivate(0))
d(new FileRefPrivate())
{
}
FileRef::FileRef(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle) :
d(new FileRefPrivate(createInternal(fileName, readAudioProperties, audioPropertiesStyle)))
d(new FileRefPrivate())
{
parse(fileName, readAudioProperties, audioPropertiesStyle);
}
FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) :
d(new FileRefPrivate(createInternal(stream, readAudioProperties, audioPropertiesStyle)))
d(new FileRefPrivate())
{
parse(stream, readAudioProperties, audioPropertiesStyle);
}
FileRef::FileRef(File *file) :
d(new FileRefPrivate(file))
d(new FileRefPrivate())
{
d->file = file;
}
FileRef::FileRef(const FileRef &ref) :
@@ -279,6 +395,7 @@ StringList FileRef::defaultFileExtensions()
l.append("ogg");
l.append("flac");
l.append("oga");
l.append("opus");
l.append("mp3");
l.append("mpc");
l.append("wv");
@@ -295,6 +412,8 @@ StringList FileRef::defaultFileExtensions()
l.append("asf");
l.append("aif");
l.append("aiff");
l.append("afc");
l.append("aifc");
l.append("wav");
l.append("ape");
l.append("mod");
@@ -341,3 +460,61 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
{
return createInternal(fileName, readAudioProperties, audioPropertiesStyle);
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void FileRef::parse(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
// Try user-defined resolvers.
d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
// Try to resolve file types based on the file extension.
d->stream = new FileStream(fileName);
d->file = detectByExtension(d->stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
// At last, try to resolve file types based on the actual content.
d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
// Stream have to be closed here if failed to resolve file types.
delete d->stream;
d->stream = 0;
}
void FileRef::parse(IOStream *stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
// Try user-defined stream resolvers.
d->file = detectByResolvers(stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
// Try user-defined resolvers.
d->file = detectByResolvers(stream->name(), readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
// Try to resolve file types based on the file extension.
d->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
// At last, try to resolve file types based on the actual content of the file.
d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
}

View File

@@ -108,6 +108,16 @@ namespace TagLib {
audioPropertiesStyle = AudioProperties::Average) const = 0;
};
class TAGLIB_EXPORT StreamTypeResolver : public FileTypeResolver
{
TAGLIB_IGNORE_MISSING_DESTRUCTOR
public:
virtual File *createFileFromStream(IOStream *stream,
bool readAudioProperties = true,
AudioProperties::ReadStyle
audioPropertiesStyle = AudioProperties::Average) const = 0;
};
/*!
* Creates a null FileRef.
*/
@@ -166,8 +176,8 @@ namespace TagLib {
* \warning This pointer will become invalid when this FileRef and all
* copies pass out of scope.
*
* \warning Do not cast it to any subclasses of \class Tag.
* Use tag returning methods of appropriate subclasses of \class File instead.
* \warning Do not cast it to any subclasses of Tag.
* Use tag returning methods of appropriate subclasses of File instead.
*
* \see File::tag()
*/
@@ -268,14 +278,16 @@ namespace TagLib {
* \note You generally shouldn't use this method, but instead the constructor
* directly.
*
* \deprecated
* \deprecated Use FileRef(FileName, bool, AudioProperties::ReadStyle).
*/
static File *create(FileName fileName,
bool readAudioProperties = true,
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
private:
void parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
void parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
class FileRefPrivate;
FileRefPrivate *d;
};

View File

@@ -55,7 +55,7 @@ namespace
const long MaxPaddingLegnth = 1024 * 1024;
const char LastBlockFlag = '\x80';
}
} // namespace
class FLAC::File::FilePrivate
{
@@ -95,6 +95,18 @@ public:
bool scanned;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool FLAC::File::isSupported(IOStream *stream)
{
// A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede.
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
return (buffer.find("fLaC") >= 0);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
@@ -168,23 +180,31 @@ bool FLAC::File::save()
}
// Create new vorbis comments
Tag::duplicate(&d->tag, xiphComment(true), false);
if(!hasXiphComment())
Tag::duplicate(&d->tag, xiphComment(true), false);
d->xiphCommentData = xiphComment()->render(false);
// Replace metadata blocks
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
MetadataBlock *commentBlock =
new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData);
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end();) {
if((*it)->code() == MetadataBlock::VorbisComment) {
// Set the new Vorbis Comment block
// Remove the old Vorbis Comment block
delete *it;
d->blocks.erase(it);
break;
it = d->blocks.erase(it);
continue;
}
if(commentBlock && (*it)->code() == MetadataBlock::Picture) {
// Set the new Vorbis Comment block before the first picture block
d->blocks.insert(it, commentBlock);
commentBlock = 0;
}
++it;
}
d->blocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData));
if(commentBlock)
d->blocks.append(commentBlock);
// Render data for the metadata blocks
@@ -198,7 +218,6 @@ bool FLAC::File::save()
}
// Compute the amount of padding, and append that to data.
// TODO: Should be calculated in offset_t in taglib2.
long originalLength = d->streamStart - d->flacStart;
long paddingLength = originalLength - data.size() - 4;
@@ -298,11 +317,7 @@ bool FLAC::File::save()
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
{
if(!create || d->tag[FlacID3v2Index])
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
d->tag.set(FlacID3v2Index, new ID3v2::Tag);
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, create);
}
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
@@ -482,6 +497,11 @@ void FLAC::File::scan()
seek(nextBlockOffset);
const ByteVector header = readBlock(4);
if(header.size() != 4) {
debug("FLAC::File::scan() -- Failed to read a block header");
setValid(false);
return;
}
// Header format (from spec):
// <1> Last-metadata-block flag
@@ -507,7 +527,9 @@ void FLAC::File::scan()
return;
}
if(blockLength == 0 && blockType != MetadataBlock::Padding) {
if(blockLength == 0
&& blockType != MetadataBlock::Padding && blockType != MetadataBlock::SeekTable)
{
debug("FLAC::File::scan() -- Zero-sized metadata block found");
setValid(false);
return;

View File

@@ -238,9 +238,9 @@ namespace TagLib {
* when
*
* \see ID3v2FrameFactory
* \deprecated This value should be passed in via the constructor
* \deprecated This value should be passed in via the constructor.
*/
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
TAGLIB_DEPRECATED void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
/*!
* Returns the block of data used by FLAC::Properties for parsing the
@@ -248,7 +248,7 @@ namespace TagLib {
*
* \deprecated Always returns an empty vector.
*/
ByteVector streamInfoData(); // BIC: remove
TAGLIB_DEPRECATED ByteVector streamInfoData(); // BIC: remove
/*!
* Returns the length of the audio-stream, used by FLAC::Properties for
@@ -256,7 +256,7 @@ namespace TagLib {
*
* \deprecated Always returns zero.
*/
long streamLength(); // BIC: remove
TAGLIB_DEPRECATED long streamLength(); // BIC: remove
/*!
* Returns a list of pictures attached to the FLAC file.
@@ -318,6 +318,15 @@ namespace TagLib {
*/
bool hasID3v2Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as a FLAC
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);

View File

@@ -50,14 +50,14 @@ public:
ByteVector data;
};
FLAC::Picture::Picture()
FLAC::Picture::Picture() :
d(new PicturePrivate())
{
d = new PicturePrivate;
}
FLAC::Picture::Picture(const ByteVector &data)
FLAC::Picture::Picture(const ByteVector &data) :
d(new PicturePrivate())
{
d = new PicturePrivate;
parse(data);
}

View File

@@ -70,9 +70,9 @@ namespace TagLib {
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
* \deprecated Use lengthInSeconds().
*/
virtual int length() const;
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
@@ -118,9 +118,9 @@ namespace TagLib {
*
* \note This method is just an alias of bitsPerSample().
*
* \deprecated
* \deprecated Use bitsPerSample().
*/
int sampleWidth() const;
TAGLIB_DEPRECATED int sampleWidth() const;
/*!
* Return the number of sample frames.

View File

@@ -39,11 +39,10 @@ public:
ByteVector data;
};
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data)
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) :
d(new UnknownMetadataBlockPrivate())
{
d = new UnknownMetadataBlockPrivate;
d->code = code;
//debug(String(data.toHex()));
d->data = data;
}

View File

@@ -37,7 +37,7 @@ class IT::File::FilePrivate
{
public:
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
: tag(), properties(propertiesStyle)
: properties(propertiesStyle)
{
}
@@ -113,7 +113,7 @@ bool IT::File::save()
// write comment as instrument and sample names:
StringList lines = d->tag.comment().split("\n");
for(unsigned short i = 0; i < instrumentCount; ++ i) {
seek(192L + length + ((long)i << 2));
seek(192L + length + (static_cast<long>(i) << 2));
unsigned long instrumentOffset = 0;
if(!readU32L(instrumentOffset))
return false;
@@ -128,14 +128,14 @@ bool IT::File::save()
}
for(unsigned short i = 0; i < sampleCount; ++ i) {
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
seek(192L + length + (static_cast<long>(instrumentCount) << 2) + (static_cast<long>(i) << 2));
unsigned long sampleOffset = 0;
if(!readU32L(sampleOffset))
return false;
seek(sampleOffset + 20);
if((unsigned int)(i + instrumentCount) < lines.size())
if(static_cast<unsigned int>(i + instrumentCount) < lines.size())
writeString(lines[i + instrumentCount], 25);
else
writeString(String(), 25);
@@ -152,7 +152,7 @@ bool IT::File::save()
// terminating NUL but it does not hurt to add one:
if(message.size() > 7999)
message.resize(7999);
message.append((char)0);
message.append(static_cast<char>(0));
unsigned short special = 0;
unsigned short messageLength = 0;
@@ -239,7 +239,7 @@ void IT::File::read(bool)
seek(messageOffset);
ByteVector messageBytes = readBlock(messageLength);
READ_ASSERT(messageBytes.size() == messageLength);
int index = messageBytes.find((char) 0);
int index = messageBytes.find(static_cast<char>(0));
if(index > -1)
messageBytes.resize(index, 0);
messageBytes.replace('\r', '\n');
@@ -258,7 +258,7 @@ void IT::File::read(bool)
// But this always gives 64 channels for all my files anyway.
// Strangely VLC does report other values. I wonder how VLC
// gets it's values.
if((unsigned char) pannings[i] < 128 && volumes[i] > 0)
if(static_cast<unsigned char>(pannings[i]) < 128 && volumes[i] > 0)
++channels;
}
d->properties.setChannels(channels);
@@ -277,10 +277,10 @@ void IT::File::read(bool)
// in the instrument/sample names and more characters
// afterwards. The spec does not mention such a case.
// Currently I just discard anything after a nil, but
// e.g. VLC seems to interprete a nil as a space. I
// e.g. VLC seems to interpret a nil as a space. I
// don't know what is the proper behaviour.
for(unsigned short i = 0; i < instrumentCount; ++ i) {
seek(192L + length + ((long)i << 2));
seek(192L + length + (static_cast<long>(i) << 2));
READ_U32L_AS(instrumentOffset);
seek(instrumentOffset);
@@ -296,7 +296,7 @@ void IT::File::read(bool)
}
for(unsigned short i = 0; i < sampleCount; ++ i) {
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
seek(192L + length + (static_cast<long>(instrumentCount) << 2) + (static_cast<long>(i) << 2));
READ_U32L_AS(sampleOffset);
seek(sampleOffset);

View File

@@ -70,7 +70,7 @@ public:
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
AudioProperties(propertiesStyle),
d(new PropertiesPrivate)
d(new PropertiesPrivate())
{
}

View File

@@ -49,7 +49,7 @@ bool Mod::FileBase::readString(String &s, unsigned long size)
{
ByteVector data(readBlock(size));
if(data.size() < size) return false;
int index = data.find((char) 0);
int index = data.find(static_cast<char>(0));
if(index > -1)
{
data.resize(index);

View File

@@ -46,7 +46,7 @@ public:
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
AudioProperties(propertiesStyle),
d(new PropertiesPrivate)
d(new PropertiesPrivate())
{
}

View File

@@ -43,9 +43,9 @@ public:
String trackerName;
};
Mod::Tag::Tag() : TagLib::Tag()
Mod::Tag::Tag() :
d(new TagPrivate())
{
d = new TagPrivate;
}
Mod::Tag::~Tag()

View File

@@ -31,7 +31,7 @@
using namespace TagLib;
const char *MP4::Atom::containers[11] = {
const char *const MP4::Atom::containers[11] = {
"moov", "udta", "mdia", "meta", "ilst",
"stbl", "minf", "moof", "traf", "trak",
"stsd"
@@ -54,24 +54,25 @@ MP4::Atom::Atom(File *file)
length = header.toUInt();
if(length == 1) {
if(length == 0) {
// The last atom which extends to the end of the file.
length = file->length() - offset;
}
else if(length == 1) {
// The atom has a 64-bit length.
const long long longLength = file->readBlock(8).toLongLong();
if(sizeof(long) == sizeof(long long)) {
if(longLength <= LONG_MAX) {
// The actual length fits in long. That's always the case if long is 64-bit.
length = static_cast<long>(longLength);
}
else {
if(longLength <= LONG_MAX) {
// The atom has a 64-bit length, but it's actually a 31-bit value
length = static_cast<long>(longLength);
}
else {
debug("MP4: 64-bit atoms are not supported");
length = 0;
file->seek(0, File::End);
return;
}
debug("MP4: 64-bit atoms are not supported");
length = 0;
file->seek(0, File::End);
return;
}
}
if(length < 8) {
debug("MP4: Invalid atom size");
length = 0;
@@ -84,7 +85,25 @@ MP4::Atom::Atom(File *file)
for(int i = 0; i < numContainers; i++) {
if(name == containers[i]) {
if(name == "meta") {
file->seek(4, File::Current);
long posAfterMeta = file->tell();
ByteVector nextSize = file->readBlock(8).mid(4, 4);
static const char *const metaChildrenNames[] = {
"hdlr", "ilst", "mhdr", "ctry", "lang"
};
bool metaIsFullAtom = true;
for(size_t j = 0;
j < sizeof(metaChildrenNames) / sizeof(metaChildrenNames[0]);
++j) {
if(nextSize == metaChildrenNames[j]) {
// meta is not a full atom (i.e. not followed by version, flags). It
// is followed by the size and type of the first child atom.
metaIsFullAtom = false;
break;
}
}
// Only skip next four bytes, which contain version and flags, if meta
// is a full atom.
file->seek(posAfterMeta + (metaIsFullAtom ? 4 : 0));
}
else if(name == "stsd") {
file->seek(8, File::Current);

View File

@@ -74,7 +74,7 @@ namespace TagLib {
typedef TagLib::List<AtomData> AtomDataList;
class Atom
class TAGLIB_EXPORT Atom
{
public:
Atom(File *file);
@@ -88,11 +88,11 @@ namespace TagLib {
AtomList children;
private:
static const int numContainers = 11;
static const char *containers[11];
static const char *const containers[11];
};
//! Root-level atoms
class Atoms
class TAGLIB_EXPORT Atoms
{
public:
Atoms(File *file);

View File

@@ -34,7 +34,6 @@ class MP4::CoverArt::CoverArtPrivate : public RefCounter
{
public:
CoverArtPrivate() :
RefCounter(),
format(MP4::CoverArt::JPEG) {}
Format format;

View File

@@ -26,6 +26,8 @@
#include <tdebug.h>
#include <tstring.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "mp4atom.h"
#include "mp4tag.h"
#include "mp4file.h"
@@ -47,7 +49,7 @@ namespace
return true;
}
}
} // namespace
class MP4::File::FilePrivate
{
@@ -69,6 +71,22 @@ public:
MP4::Properties *properties;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool MP4::File::isSupported(IOStream *stream)
{
// An MP4 file has to have an "ftyp" box first.
const ByteVector id = Utils::readHeader(stream, 8, false);
return id.containsAt("ftyp", 4);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
@@ -157,6 +175,26 @@ MP4::File::save()
return d->tag->save();
}
bool
MP4::File::strip(int tags)
{
if(readOnly()) {
debug("MP4::File::strip() - Cannot strip tags from a read only file.");
return false;
}
if(!isValid()) {
debug("MP4::File::strip() -- Cannot strip tags from an invalid file.");
return false;
}
if(tags & MP4) {
return d->tag->strip();
}
return true;
}
bool
MP4::File::hasMP4Tag() const
{

View File

@@ -48,6 +48,19 @@ namespace TagLib {
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* This set of flags is used for strip() and is suitable for
* being OR-ed together.
*/
enum TagTypes {
//! Empty set. Matches no tag types.
NoTags = 0x0000,
//! Matches MP4 tags.
MP4 = 0x0001,
//! Matches all tag types.
AllTags = 0xffff
};
/*!
* Constructs an MP4 file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
@@ -114,12 +127,30 @@ namespace TagLib {
*/
bool save();
/*!
* 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.
*
* \note This will update the file immediately.
*/
bool strip(int tags = AllTags);
/*!
* Returns whether or not the file on disk actually has an MP4 tag, or the
* file has a Metadata Item List (ilst) atom.
*/
bool hasMP4Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as an ASF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
void read(bool readProperties);

View File

@@ -34,7 +34,6 @@ class MP4::Item::ItemPrivate : public RefCounter
{
public:
ItemPrivate() :
RefCounter(),
valid(true),
atomDataType(TypeUndefined) {}

View File

@@ -31,6 +31,27 @@
using namespace TagLib;
namespace
{
// Calculate the total bytes used by audio data, used to calculate the bitrate
long long calculateMdatLength(const MP4::AtomList &list)
{
long long totalLength = 0;
for(MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) {
long length = (*it)->length;
if(length == 0)
return 0; // for safety, see checkValid() in mp4file.cpp
if((*it)->name == "mdat")
totalLength += length;
totalLength += calculateMdatLength((*it)->children);
}
return totalLength;
}
} // namespace
class MP4::Properties::PropertiesPrivate
{
public:
@@ -167,7 +188,7 @@ MP4::Properties::read(File *file, Atoms *atoms)
file->seek(mdhd->offset);
data = file->readBlock(mdhd->length);
const unsigned int version = data[8];
const unsigned int version = data.at(8);
long long unit;
long long length;
if(version == 1) {
@@ -175,11 +196,11 @@ MP4::Properties::read(File *file, Atoms *atoms)
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
unit = data.toLongLong(28U);
length = data.toLongLong(36U);
unit = data.toUInt(28U);
length = data.toLongLong(32U);
}
else {
if(data.size() < 24 + 4) {
if(data.size() < 24 + 8) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
@@ -201,19 +222,26 @@ MP4::Properties::read(File *file, Atoms *atoms)
d->channels = data.toShort(40U);
d->bitsPerSample = data.toShort(42U);
d->sampleRate = data.toUInt(46U);
if(data.containsAt("esds", 56) && data[64] == 0x03) {
if(data.containsAt("esds", 56) && data.at(64) == 0x03) {
unsigned int pos = 65;
if(data.containsAt("\x80\x80\x80", pos)) {
pos += 3;
}
pos += 4;
if(data[pos] == 0x04) {
if(data.at(pos) == 0x04) {
pos += 1;
if(data.containsAt("\x80\x80\x80", pos)) {
pos += 3;
}
pos += 10;
d->bitrate = static_cast<int>((data.toUInt(pos) + 500) / 1000.0 + 0.5);
const unsigned int bitrateValue = data.toUInt(pos);
if(bitrateValue != 0 || d->length <= 0) {
d->bitrate = static_cast<int>((bitrateValue + 500) / 1000.0 + 0.5);
}
else {
d->bitrate = static_cast<int>(
(calculateMdatLength(atoms->atoms) * 8) / d->length);
}
}
}
}
@@ -224,6 +252,13 @@ MP4::Properties::read(File *file, Atoms *atoms)
d->channels = data.at(73);
d->bitrate = static_cast<int>(data.toUInt(80U) / 1000.0 + 0.5);
d->sampleRate = data.toUInt(84U);
if(d->bitrate == 0 && d->length > 0) {
// There are files which do not contain a nominal bitrate, e.g. those
// generated by refalac64.exe. Calculate the bitrate from the audio
// data size (mdat atoms) and the duration.
d->bitrate = (calculateMdatLength(atoms->atoms) * 8) / d->length;
}
}
}

View File

@@ -55,9 +55,9 @@ namespace TagLib {
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
* \deprecated Use lengthInSeconds().
*/
virtual int length() const;
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to

View File

@@ -71,14 +71,26 @@ MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) :
parseIntPair(atom);
}
else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" ||
atom->name == "hdvd") {
atom->name == "hdvd" || atom->name == "shwm") {
parseBool(atom);
}
else if(atom->name == "tmpo") {
else if(atom->name == "tmpo" || atom->name == "\251mvi" || atom->name == "\251mvc") {
parseInt(atom);
}
else if(atom->name == "rate") {
AtomDataList data = parseData2(atom);
if(!data.isEmpty()) {
AtomData val = data[0];
if (val.type == TypeUTF8) {
addItem(atom->name, StringList(String(val.data, String::UTF8)));
} else {
addItem(atom->name, static_cast<int>(val.data.toShort()));
}
}
}
else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" ||
atom->name == "sfID" || atom->name == "atID" || atom->name == "geID") {
atom->name == "sfID" || atom->name == "atID" || atom->name == "geID" ||
atom->name == "cmID") {
parseUInt(atom);
}
else if(atom->name == "plID") {
@@ -93,6 +105,9 @@ MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) :
else if(atom->name == "covr") {
parseCovr(atom);
}
else if(atom->name == "purl" || atom->name == "egid") {
parseText(atom, -1);
}
else {
parseText(atom);
}
@@ -125,7 +140,7 @@ MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm)
debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\"");
return result;
}
else if(i == 1 && name != "name") {
if(i == 1 && name != "name") {
debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\"");
return result;
}
@@ -162,7 +177,7 @@ MP4::Tag::parseInt(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(!data.isEmpty()) {
addItem(atom->name, (int)data[0].toShort());
addItem(atom->name, static_cast<int>(data[0].toShort()));
}
}
@@ -198,7 +213,7 @@ MP4::Tag::parseGnre(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(!data.isEmpty()) {
int idx = (int)data[0].toShort();
int idx = static_cast<int>(data[0].toShort());
if(idx > 0) {
addItem("\251gen", StringList(ID3v1::genre(idx - 1)));
}
@@ -290,7 +305,7 @@ MP4::Tag::parseCovr(const MP4::Atom *atom)
const int length = static_cast<int>(data.toUInt(pos));
if(length < 12) {
debug("MP4: Too short atom");
break;;
break;
}
const ByteVector name = data.mid(pos + 4, 4);
@@ -472,14 +487,26 @@ MP4::Tag::save()
else if(name == "disk") {
data.append(renderIntPairNoTrailing(name.data(String::Latin1), it->second));
}
else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") {
else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd" ||
name == "shwm") {
data.append(renderBool(name.data(String::Latin1), it->second));
}
else if(name == "tmpo") {
else if(name == "tmpo" || name == "\251mvi" || name == "\251mvc") {
data.append(renderInt(name.data(String::Latin1), it->second));
}
else if (name == "rate") {
const MP4::Item& item = it->second;
StringList value = item.toStringList();
if (value.isEmpty()) {
data.append(renderInt(name.data(String::Latin1), item));
}
else {
data.append(renderText(name.data(String::Latin1), item));
}
}
else if(name == "tvsn" || name == "tves" || name == "cnID" ||
name == "sfID" || name == "atID" || name == "geID") {
name == "sfID" || name == "atID" || name == "geID" ||
name == "cmID") {
data.append(renderUInt(name.data(String::Latin1), it->second));
}
else if(name == "plID") {
@@ -491,6 +518,9 @@ MP4::Tag::save()
else if(name == "covr") {
data.append(renderCovr(name.data(String::Latin1), it->second));
}
else if(name == "purl" || name == "egid") {
data.append(renderText(name.data(String::Latin1), it->second, TypeImplicit));
}
else if(name.size() == 4){
data.append(renderText(name.data(String::Latin1), it->second));
}
@@ -511,6 +541,19 @@ MP4::Tag::save()
return true;
}
bool
MP4::Tag::strip()
{
d->items.clear();
AtomList path = d->atoms->path("moov", "udta", "meta", "ilst");
if(path.size() == 4) {
saveExisting(ByteVector(), path);
}
return true;
}
void
MP4::Tag::updateParents(const AtomList &path, long delta, int ignore)
{
@@ -669,20 +712,40 @@ MP4::Tag::saveExisting(ByteVector data, const AtomList &path)
}
long delta = data.size() - length;
if(delta > 0 || (delta < 0 && delta > -8)) {
data.append(padIlst(data));
delta = data.size() - length;
}
else if(delta < 0) {
data.append(padIlst(data, -delta - 8));
delta = 0;
}
if(!data.isEmpty()) {
if(delta > 0 || (delta < 0 && delta > -8)) {
data.append(padIlst(data));
delta = data.size() - length;
}
else if(delta < 0) {
data.append(padIlst(data, -delta - 8));
delta = 0;
}
d->file->insert(data, offset, length);
d->file->insert(data, offset, length);
if(delta) {
updateParents(path, delta, 1);
updateOffsets(delta, offset);
if(delta) {
updateParents(path, delta, 1);
updateOffsets(delta, offset);
}
}
else {
// Strip meta if data is empty, only the case when called from strip().
MP4::Atom *udta = *(--it);
AtomList &udtaChildren = udta->children;
AtomList::Iterator metaIt = udtaChildren.find(meta);
if(metaIt != udtaChildren.end()) {
offset = meta->offset;
delta = - meta->length;
udtaChildren.erase(metaIt);
d->file->removeBlock(meta->offset, meta->length);
delete meta;
if(delta) {
updateParents(path, delta, 2);
updateOffsets(delta, offset);
}
}
}
}
@@ -745,43 +808,63 @@ MP4::Tag::track() const
void
MP4::Tag::setTitle(const String &value)
{
d->items["\251nam"] = StringList(value);
setTextItem("\251nam", value);
}
void
MP4::Tag::setArtist(const String &value)
{
d->items["\251ART"] = StringList(value);
setTextItem("\251ART", value);
}
void
MP4::Tag::setAlbum(const String &value)
{
d->items["\251alb"] = StringList(value);
setTextItem("\251alb", value);
}
void
MP4::Tag::setComment(const String &value)
{
d->items["\251cmt"] = StringList(value);
setTextItem("\251cmt", value);
}
void
MP4::Tag::setGenre(const String &value)
{
d->items["\251gen"] = StringList(value);
setTextItem("\251gen", value);
}
void
MP4::Tag::setTextItem(const String &key, const String &value)
{
if (!value.isEmpty()) {
d->items[key] = StringList(value);
} else {
d->items.erase(key);
}
}
void
MP4::Tag::setYear(unsigned int value)
{
d->items["\251day"] = StringList(String::number(value));
if (value == 0) {
d->items.erase("\251day");
}
else {
d->items["\251day"] = StringList(String::number(value));
}
}
void
MP4::Tag::setTrack(unsigned int value)
{
d->items["trkn"] = MP4::Item(value, 0);
if (value == 0) {
d->items.erase("trkn");
}
else {
d->items["trkn"] = MP4::Item(value, 0);
}
}
bool MP4::Tag::isEmpty() const
@@ -821,67 +904,89 @@ bool MP4::Tag::contains(const String &key) const
namespace
{
const char *keyTranslation[][2] = {
{ "\251nam", "TITLE" },
{ "\251ART", "ARTIST" },
{ "\251alb", "ALBUM" },
{ "\251cmt", "COMMENT" },
{ "\251gen", "GENRE" },
{ "\251day", "DATE" },
{ "\251wrt", "COMPOSER" },
{ "\251grp", "GROUPING" },
{ "aART", "ALBUMARTIST" },
{ "trkn", "TRACKNUMBER" },
{ "disk", "DISCNUMBER" },
{ "cpil", "COMPILATION" },
{ "tmpo", "BPM" },
{ "cprt", "COPYRIGHT" },
{ "\251lyr", "LYRICS" },
{ "\251too", "ENCODEDBY" },
{ "soal", "ALBUMSORT" },
{ "soaa", "ALBUMARTISTSORT" },
{ "soar", "ARTISTSORT" },
{ "sonm", "TITLESORT" },
{ "soco", "COMPOSERSORT" },
{ "sosn", "SHOWSORT" },
{ "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" },
{ "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
{ "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
{ "----:com.apple.iTunes:ASIN", "ASIN" },
{ "----:com.apple.iTunes:LABEL", "LABEL" },
{ "----:com.apple.iTunes:LYRICIST", "LYRICIST" },
{ "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" },
{ "----:com.apple.iTunes:REMIXER", "REMIXER" },
{ "----:com.apple.iTunes:ENGINEER", "ENGINEER" },
{ "----:com.apple.iTunes:PRODUCER", "PRODUCER" },
{ "----:com.apple.iTunes:DJMIXER", "DJMIXER" },
{ "----:com.apple.iTunes:MIXER", "MIXER" },
{ "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" },
{ "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" },
{ "----:com.apple.iTunes:MOOD", "MOOD" },
{ "----:com.apple.iTunes:ISRC", "ISRC" },
{ "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" },
{ "----:com.apple.iTunes:BARCODE", "BARCODE" },
{ "----:com.apple.iTunes:SCRIPT", "SCRIPT" },
{ "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" },
{ "----:com.apple.iTunes:LICENSE", "LICENSE" },
{ "----:com.apple.iTunes:MEDIA", "MEDIA" },
const std::pair<const char *, const char *> keyTranslation[] = {
std::make_pair("\251nam", "TITLE"),
std::make_pair("\251ART", "ARTIST"),
std::make_pair("\251alb", "ALBUM"),
std::make_pair("\251cmt", "COMMENT"),
std::make_pair("\251gen", "GENRE"),
std::make_pair("\251day", "DATE"),
std::make_pair("\251wrt", "COMPOSER"),
std::make_pair("\251grp", "GROUPING"),
std::make_pair("aART", "ALBUMARTIST"),
std::make_pair("trkn", "TRACKNUMBER"),
std::make_pair("disk", "DISCNUMBER"),
std::make_pair("cpil", "COMPILATION"),
std::make_pair("tmpo", "BPM"),
std::make_pair("cprt", "COPYRIGHT"),
std::make_pair("\251lyr", "LYRICS"),
std::make_pair("\251too", "ENCODEDBY"),
std::make_pair("soal", "ALBUMSORT"),
std::make_pair("soaa", "ALBUMARTISTSORT"),
std::make_pair("soar", "ARTISTSORT"),
std::make_pair("sonm", "TITLESORT"),
std::make_pair("soco", "COMPOSERSORT"),
std::make_pair("sosn", "SHOWSORT"),
std::make_pair("shwm", "SHOWWORKMOVEMENT"),
std::make_pair("pgap", "GAPLESSPLAYBACK"),
std::make_pair("pcst", "PODCAST"),
std::make_pair("catg", "PODCASTCATEGORY"),
std::make_pair("desc", "PODCASTDESC"),
std::make_pair("egid", "PODCASTID"),
std::make_pair("purl", "PODCASTURL"),
std::make_pair("tves", "TVEPISODE"),
std::make_pair("tven", "TVEPISODEID"),
std::make_pair("tvnn", "TVNETWORK"),
std::make_pair("tvsn", "TVSEASON"),
std::make_pair("tvsh", "TVSHOW"),
std::make_pair("\251wrk", "WORK"),
std::make_pair("\251mvn", "MOVEMENTNAME"),
std::make_pair("\251mvi", "MOVEMENTNUMBER"),
std::make_pair("\251mvc", "MOVEMENTCOUNT"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Release Track Id", "MUSICBRAINZ_RELEASETRACKID"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Album Release Country", "RELEASECOUNTRY"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Album Status", "RELEASESTATUS"),
std::make_pair("----:com.apple.iTunes:MusicBrainz Album Type", "RELEASETYPE"),
std::make_pair("----:com.apple.iTunes:ARTISTS", "ARTISTS"),
std::make_pair("----:com.apple.iTunes:originaldate", "ORIGINALDATE"),
std::make_pair("----:com.apple.iTunes:ASIN", "ASIN"),
std::make_pair("----:com.apple.iTunes:LABEL", "LABEL"),
std::make_pair("----:com.apple.iTunes:LYRICIST", "LYRICIST"),
std::make_pair("----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR"),
std::make_pair("----:com.apple.iTunes:REMIXER", "REMIXER"),
std::make_pair("----:com.apple.iTunes:ENGINEER", "ENGINEER"),
std::make_pair("----:com.apple.iTunes:PRODUCER", "PRODUCER"),
std::make_pair("----:com.apple.iTunes:DJMIXER", "DJMIXER"),
std::make_pair("----:com.apple.iTunes:MIXER", "MIXER"),
std::make_pair("----:com.apple.iTunes:SUBTITLE", "SUBTITLE"),
std::make_pair("----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE"),
std::make_pair("----:com.apple.iTunes:MOOD", "MOOD"),
std::make_pair("----:com.apple.iTunes:ISRC", "ISRC"),
std::make_pair("----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER"),
std::make_pair("----:com.apple.iTunes:BARCODE", "BARCODE"),
std::make_pair("----:com.apple.iTunes:SCRIPT", "SCRIPT"),
std::make_pair("----:com.apple.iTunes:LANGUAGE", "LANGUAGE"),
std::make_pair("----:com.apple.iTunes:LICENSE", "LICENSE"),
std::make_pair("----:com.apple.iTunes:MEDIA", "MEDIA"),
};
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
String translateKey(const String &key)
{
for(size_t i = 0; i < keyTranslationSize; ++i) {
if(key == keyTranslation[i][0])
return keyTranslation[i][1];
if(key == keyTranslation[i].first)
return keyTranslation[i].second;
}
return String();
}
}
} // namespace
PropertyMap MP4::Tag::properties() const
{
@@ -897,10 +1002,12 @@ PropertyMap MP4::Tag::properties() const
}
props[key] = value;
}
else if(key == "BPM") {
else if(key == "BPM" || key == "MOVEMENTNUMBER" || key == "MOVEMENTCOUNT" ||
key == "TVEPISODE" || key == "TVSEASON") {
props[key] = String::number(it->second.toInt());
}
else if(key == "COMPILATION") {
else if(key == "COMPILATION" || key == "SHOWWORKMOVEMENT" ||
key == "GAPLESSPLAYBACK" || key == "PODCAST") {
props[key] = String::number(it->second.toBool());
}
else {
@@ -924,9 +1031,8 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props)
{
static Map<String, String> reverseKeyMap;
if(reverseKeyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
for(int i = 0; i < numKeys; i++) {
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
for(size_t i = 0; i < keyTranslationSize; i++) {
reverseKeyMap[keyTranslation[i].second] = keyTranslation[i].first;
}
}
@@ -942,21 +1048,25 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props)
if(reverseKeyMap.contains(it->first)) {
String name = reverseKeyMap[it->first];
if((it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") && !it->second.isEmpty()) {
int first = 0, second = 0;
StringList parts = StringList::split(it->second.front(), "/");
if(!parts.isEmpty()) {
first = parts[0].toInt();
int first = parts[0].toInt();
int second = 0;
if(parts.size() > 1) {
second = parts[1].toInt();
}
d->items[name] = MP4::Item(first, second);
}
}
else if(it->first == "BPM" && !it->second.isEmpty()) {
else if((it->first == "BPM" || it->first == "MOVEMENTNUMBER" ||
it->first == "MOVEMENTCOUNT" || it->first == "TVEPISODE" ||
it->first == "TVSEASON") && !it->second.isEmpty()) {
int value = it->second.front().toInt();
d->items[name] = MP4::Item(value);
}
else if(it->first == "COMPILATION" && !it->second.isEmpty()) {
else if((it->first == "COMPILATION" || it->first == "SHOWWORKMOVEMENT" ||
it->first == "GAPLESSPLAYBACK" || it->first == "PODCAST") &&
!it->second.isEmpty()) {
bool value = (it->second.front().toInt() != 0);
d->items[name] = MP4::Item(value);
}

View File

@@ -40,9 +40,9 @@ namespace TagLib {
namespace MP4 {
/*!
* \deprecated
* \deprecated Use ItemMap.
*/
typedef TagLib::Map<String, Item> ItemListMap;
TAGLIB_DEPRECATED typedef TagLib::Map<String, Item> ItemListMap;
typedef TagLib::Map<String, Item> ItemMap;
class TAGLIB_EXPORT Tag: public TagLib::Tag
@@ -72,9 +72,9 @@ namespace TagLib {
virtual bool isEmpty() const;
/*!
* \deprecated Use the item() and setItem() API instead
* \deprecated Use the item() and setItem() API instead.
*/
ItemMap &itemListMap();
TAGLIB_DEPRECATED ItemMap &itemListMap();
/*!
* Returns a string-keyed map of the MP4::Items for this tag.
@@ -102,10 +102,22 @@ namespace TagLib {
*/
bool contains(const String &key) const;
/*!
* Saves the associated file with the tag stripped.
*/
bool strip();
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList& properties);
PropertyMap setProperties(const PropertyMap &properties);
protected:
/*!
* Sets the value of \a key to \a value, overwriting any previous value.
* If \a value is empty, the item is removed.
*/
void setTextItem(const String &key, const String &value);
private:
AtomDataList parseData2(const Atom *atom, int expectedFlags = -1,
bool freeForm = false);

View File

@@ -75,6 +75,19 @@ public:
Properties *properties;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool MPC::File::isSupported(IOStream *stream)
{
// A newer MPC file has to start with "MPCK" or "MP+", but older files don't
// have keys to do a quick check.
const ByteVector id = Utils::readHeader(stream, 4, false);
return (id == "MPCK" || id.startsWith("MP+"));
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

View File

@@ -195,10 +195,10 @@ namespace TagLib {
void strip(int tags = AllTags);
/*!
* \deprecated
* \deprecated Use strip().
* \see strip
*/
void remove(int tags = AllTags);
TAGLIB_DEPRECATED void remove(int tags = AllTags);
/*!
* Returns whether or not the file on disk actually has an ID3v1 tag.
@@ -214,6 +214,15 @@ namespace TagLib {
*/
bool hasAPETag() const;
/*!
* Returns whether or not the given \a stream can be opened as an MPC
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);

View File

@@ -49,18 +49,17 @@ public:
albumGain(0),
albumPeak(0) {}
int version;
int length;
int bitrate;
int sampleRate;
int channels;
int version;
int length;
int bitrate;
int sampleRate;
int channels;
unsigned int totalFrames;
unsigned int sampleFrames;
unsigned int trackGain;
unsigned int trackPeak;
unsigned int albumGain;
unsigned int albumPeak;
String flags;
int trackGain;
int trackPeak;
int albumGain;
int albumPeak;
};
////////////////////////////////////////////////////////////////////////////////
@@ -202,7 +201,7 @@ namespace
// This array looks weird, but the same as original MusePack code found at:
// https://www.musepack.net/index.php?pg=src
const unsigned short sftable [8] = { 44100, 48000, 37800, 32000, 0, 0, 0, 0 };
}
} // namespace
void MPC::Properties::readSV8(File *file, long streamLength)
{
@@ -299,6 +298,9 @@ void MPC::Properties::readSV8(File *file, long streamLength)
void MPC::Properties::readSV7(const ByteVector &data, long streamLength)
{
if(data.startsWith("MP+")) {
if(data.size() < 4)
return;
d->version = data[3] & 15;
if(d->version < 7)
return;
@@ -312,28 +314,28 @@ void MPC::Properties::readSV7(const ByteVector &data, long streamLength)
const unsigned int gapless = data.toUInt(5, false);
d->trackGain = data.toShort(14, false);
d->trackPeak = data.toShort(12, false);
d->trackPeak = data.toUShort(12, false);
d->albumGain = data.toShort(18, false);
d->albumPeak = data.toShort(16, false);
d->albumPeak = data.toUShort(16, false);
// convert gain info
if(d->trackGain != 0) {
int tmp = (int)((64.82 - (short)d->trackGain / 100.) * 256. + .5);
int tmp = static_cast<int>((64.82 - static_cast<short>(d->trackGain) / 100.) * 256. + .5);
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
d->trackGain = tmp;
}
if(d->albumGain != 0) {
int tmp = (int)((64.82 - d->albumGain / 100.) * 256. + .5);
int tmp = static_cast<int>((64.82 - d->albumGain / 100.) * 256. + .5);
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
d->albumGain = tmp;
}
if (d->trackPeak != 0)
d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5);
d->trackPeak = static_cast<int>(log10(static_cast<double>(d->trackPeak)) * 20 * 256 + .5);
if (d->albumPeak != 0)
d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5);
d->albumPeak = static_cast<int>(log10(static_cast<double>(d->albumPeak)) * 20 * 256 + .5);
bool trueGapless = (gapless >> 31) & 0x0001;
if(trueGapless) {

View File

@@ -72,9 +72,9 @@ namespace TagLib {
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
* \deprecated Use lengthInSeconds().
*/
virtual int length() const;
TAGLIB_DEPRECATED virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to

View File

@@ -29,7 +29,7 @@ using namespace TagLib;
namespace
{
const wchar_t *genres[] = {
const wchar_t *const genres[] = {
L"Blues",
L"Classic Rock",
L"Country",
@@ -59,7 +59,7 @@ namespace
L"Ambient",
L"Trip-Hop",
L"Vocal",
L"Jazz+Funk",
L"Jazz-Funk",
L"Fusion",
L"Trance",
L"Classical",
@@ -111,16 +111,16 @@ namespace
L"Rock & Roll",
L"Hard Rock",
L"Folk",
L"Folk/Rock",
L"Folk Rock",
L"National Folk",
L"Swing",
L"Fusion",
L"Bebob",
L"Fast Fusion",
L"Bebop",
L"Latin",
L"Revival",
L"Celtic",
L"Bluegrass",
L"Avantgarde",
L"Avant-garde",
L"Gothic Rock",
L"Progressive Rock",
L"Psychedelic Rock",
@@ -155,15 +155,15 @@ namespace
L"Drum Solo",
L"A Cappella",
L"Euro-House",
L"Dance Hall",
L"Dancehall",
L"Goa",
L"Drum & Bass",
L"Club-House",
L"Hardcore",
L"Hardcore Techno",
L"Terror",
L"Indie",
L"BritPop",
L"Negerpunk",
L"Britpop",
L"Worldbeat",
L"Polsk Punk",
L"Beat",
L"Christian Gangsta Rap",
@@ -224,7 +224,7 @@ namespace
L"Psybient"
};
const int genresSize = sizeof(genres) / sizeof(genres[0]);
}
} // namespace
StringList ID3v1::genreList()
{
@@ -250,8 +250,7 @@ String ID3v1::genre(int i)
{
if(i >= 0 && i < genresSize)
return String(genres[i]); // always make a copy
else
return String();
return String();
}
int ID3v1::genreIndex(const String &name)
@@ -261,5 +260,26 @@ int ID3v1::genreIndex(const String &name)
return i;
}
// If the name was not found, try the names which have been changed
static const struct {
const wchar_t *genre;
int code;
} fixUpGenres[] = {
{ L"Jazz+Funk", 29 },
{ L"Folk/Rock", 81 },
{ L"Bebob", 85 },
{ L"Avantgarde", 90 },
{ L"Dance Hall", 125 },
{ L"Hardcore", 129 },
{ L"BritPop", 132 },
{ L"Negerpunk", 133 }
};
static const int fixUpGenresSize =
sizeof(fixUpGenres) / sizeof(fixUpGenres[0]);
for(int i = 0; i < fixUpGenresSize; ++i) {
if(name == fixUpGenres[i].genre)
return fixUpGenres[i].code;
}
return 255;
}

View File

@@ -76,8 +76,7 @@ ByteVector ID3v1::StringHandler::render(const String &s) const
{
if(s.isLatin1())
return s.data(String::Latin1);
else
return ByteVector();
return ByteVector();
}
////////////////////////////////////////////////////////////////////////////////
@@ -85,13 +84,11 @@ ByteVector ID3v1::StringHandler::render(const String &s) const
////////////////////////////////////////////////////////////////////////////////
ID3v1::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
}
ID3v1::Tag::Tag(File *file, long tagOffset) :
TagLib::Tag(),
d(new TagPrivate())
{
d->file = file;

View File

@@ -48,14 +48,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC")
AttachedPictureFrame::AttachedPictureFrame() :
Frame("APIC"),
d(new AttachedPictureFramePrivate())
{
d = new AttachedPictureFramePrivate;
}
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data)
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) :
Frame(data),
d(new AttachedPictureFramePrivate())
{
d = new AttachedPictureFramePrivate;
setData(data);
}
@@ -142,7 +144,7 @@ void AttachedPictureFrame::parseFields(const ByteVector &data)
return;
}
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
d->type = static_cast<TagLib::ID3v2::AttachedPictureFrame::Type>(data[pos++]);
d->description = readStringField(data, d->textEncoding, &pos);
d->data = data.mid(pos);
@@ -169,9 +171,10 @@ ByteVector AttachedPictureFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h)
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new AttachedPictureFramePrivate())
{
d = new AttachedPictureFramePrivate;
parseFields(fieldData(data));
}
@@ -202,7 +205,7 @@ void AttachedPictureFrameV22::parseFields(const ByteVector &data)
d->mimeType = "image/" + fixedString;
}
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
d->type = static_cast<TagLib::ID3v2::AttachedPictureFrame::Type>(data[pos++]);
d->description = readStringField(data, d->textEncoding, &pos);
d->data = data.mid(pos);

View File

@@ -37,7 +37,11 @@ class ChapterFrame::ChapterFramePrivate
{
public:
ChapterFramePrivate() :
tagHeader(0)
tagHeader(0),
startTime(0),
endTime(0),
startOffset(0),
endOffset(0)
{
embeddedFrameList.setAutoDelete(true);
}
@@ -57,9 +61,9 @@ public:
////////////////////////////////////////////////////////////////////////////////
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
ID3v2::Frame(data),
d(new ChapterFramePrivate())
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
setData(data);
}
@@ -68,10 +72,9 @@ ChapterFrame::ChapterFrame(const ByteVector &elementID,
unsigned int startTime, unsigned int endTime,
unsigned int startOffset, unsigned int endOffset,
const FrameList &embeddedFrames) :
ID3v2::Frame("CHAP")
ID3v2::Frame("CHAP"),
d(new ChapterFramePrivate())
{
d = new ChapterFramePrivate;
// setElementID has a workaround for a previously silly API where you had to
// specifically include the null byte.
@@ -198,7 +201,7 @@ String ChapterFrame::toString() const
s += ", start offset: " + String::number(d->startOffset);
if(d->endOffset != 0xFFFFFFFF)
s += ", start offset: " + String::number(d->endOffset);
s += ", end offset: " + String::number(d->endOffset);
if(!d->embeddedFrameList.isEmpty()) {
StringList frameIDs;
@@ -264,7 +267,7 @@ void ChapterFrame::parseFields(const ByteVector &data)
return;
while(embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
if(!frame)
return;
@@ -291,16 +294,18 @@ ByteVector ChapterFrame::renderFields() const
data.append(ByteVector::fromUInt(d->startOffset, true));
data.append(ByteVector::fromUInt(d->endOffset, true));
FrameList l = d->embeddedFrameList;
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
(*it)->header()->setVersion(header()->version());
data.append((*it)->render());
}
return data;
}
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
Frame(h)
Frame(h),
d(new ChapterFramePrivate())
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -57,7 +57,7 @@ namespace TagLib {
* \a startTime, end time \a endTime, start offset \a startOffset,
* end offset \a endOffset and optionally a list of embedded frames,
* whose ownership will then be taken over by this Frame, in
* \a embeededFrames;
* \a embeddedFrames;
*
* All times are in milliseconds.
*/

View File

@@ -48,15 +48,17 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM")
CommentsFrame::CommentsFrame(String::Type encoding) :
Frame("COMM"),
d(new CommentsFramePrivate())
{
d = new CommentsFramePrivate;
d->textEncoding = encoding;
}
CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data)
CommentsFrame::CommentsFrame(const ByteVector &data) :
Frame(data),
d(new CommentsFramePrivate())
{
d = new CommentsFramePrivate;
setData(data);
}
@@ -188,8 +190,9 @@ ByteVector CommentsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h)
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new CommentsFramePrivate())
{
d = new CommentsFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -46,15 +46,15 @@ public:
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame() :
Frame("ETCO")
Frame("ETCO"),
d(new EventTimingCodesFramePrivate())
{
d = new EventTimingCodesFramePrivate;
}
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new EventTimingCodesFramePrivate())
{
d = new EventTimingCodesFramePrivate;
setData(data);
}
@@ -136,9 +136,9 @@ ByteVector EventTimingCodesFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h)
: Frame(h)
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new EventTimingCodesFramePrivate())
{
d = new EventTimingCodesFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -50,14 +50,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB")
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() :
Frame("GEOB"),
d(new GeneralEncapsulatedObjectFramePrivate())
{
d = new GeneralEncapsulatedObjectFramePrivate;
}
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data)
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) :
Frame(data),
d(new GeneralEncapsulatedObjectFramePrivate())
{
d = new GeneralEncapsulatedObjectFramePrivate;
setData(data);
}
@@ -177,8 +179,9 @@ ByteVector GeneralEncapsulatedObjectFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h)
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new GeneralEncapsulatedObjectFramePrivate())
{
d = new GeneralEncapsulatedObjectFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -45,15 +45,17 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE")
OwnershipFrame::OwnershipFrame(String::Type encoding) :
Frame("OWNE"),
d(new OwnershipFramePrivate())
{
d = new OwnershipFramePrivate;
d->textEncoding = encoding;
}
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data)
OwnershipFrame::OwnershipFrame(const ByteVector &data) :
Frame(data),
d(new OwnershipFramePrivate())
{
d = new OwnershipFramePrivate;
setData(data);
}
@@ -115,6 +117,11 @@ void OwnershipFrame::parseFields(const ByteVector &data)
{
int pos = 0;
// Need at least 1 byte for the encoding
if(data.isEmpty()) {
return;
}
// Get the text encoding
d->textEncoding = String::Type(data[0]);
pos += 1;
@@ -161,8 +168,9 @@ ByteVector OwnershipFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h)
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new OwnershipFramePrivate())
{
d = new OwnershipFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -24,6 +24,7 @@
***************************************************************************/
#include "podcastframe.h"
#include <tpropertymap.h>
using namespace TagLib;
using namespace ID3v2;
@@ -38,9 +39,10 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame() : Frame("PCST")
PodcastFrame::PodcastFrame() :
Frame("PCST"),
d(new PodcastFramePrivate())
{
d = new PodcastFramePrivate;
d->fieldData = ByteVector(4, '\0');
}
@@ -54,6 +56,13 @@ String PodcastFrame::toString() const
return String();
}
PropertyMap PodcastFrame::asProperties() const
{
PropertyMap map;
map.insert("PODCAST", StringList());
return map;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
@@ -72,8 +81,9 @@ ByteVector PodcastFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) : Frame(h)
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PodcastFramePrivate())
{
d = new PodcastFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -57,6 +57,8 @@ namespace TagLib {
*/
virtual String toString() const;
PropertyMap asProperties() const;
protected:
// Reimplementations.

View File

@@ -43,14 +43,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame() : Frame("POPM")
PopularimeterFrame::PopularimeterFrame() :
Frame("POPM"),
d(new PopularimeterFramePrivate())
{
d = new PopularimeterFramePrivate;
}
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data)
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) :
Frame(data),
d(new PopularimeterFramePrivate())
{
d = new PopularimeterFramePrivate;
setData(data);
}
@@ -107,7 +109,7 @@ void PopularimeterFrame::parseFields(const ByteVector &data)
d->rating = 0;
d->counter = 0;
if(pos < size) {
d->rating = (unsigned char)(data[pos++]);
d->rating = static_cast<unsigned char>(data[pos++]);
if(pos < size) {
d->counter = data.toUInt(static_cast<unsigned int>(pos));
}
@@ -130,8 +132,9 @@ ByteVector PopularimeterFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h)
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PopularimeterFramePrivate())
{
d = new PopularimeterFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -45,15 +45,17 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame() : Frame("PRIV")
PrivateFrame::PrivateFrame() :
Frame("PRIV"),
d(new PrivateFramePrivate())
{
d = new PrivateFramePrivate;
}
PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data)
PrivateFrame::PrivateFrame(const ByteVector &data) :
Frame(data),
d(new PrivateFramePrivate())
{
d = new PrivateFramePrivate;
setData(data);
Frame::setData(data);
}
PrivateFrame::~PrivateFrame()
@@ -121,8 +123,9 @@ ByteVector PrivateFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h)
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new PrivateFramePrivate())
{
d = new PrivateFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -51,14 +51,16 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2")
RelativeVolumeFrame::RelativeVolumeFrame() :
Frame("RVA2"),
d(new RelativeVolumeFramePrivate())
{
d = new RelativeVolumeFramePrivate;
}
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data)
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) :
Frame(data),
d(new RelativeVolumeFramePrivate())
{
d = new RelativeVolumeFramePrivate;
setData(data);
}
@@ -178,7 +180,7 @@ void RelativeVolumeFrame::parseFields(const ByteVector &data)
// Each channel is at least 4 bytes.
while(pos <= (int)data.size() - 4) {
while(pos <= static_cast<int>(data.size()) - 4) {
ChannelType type = ChannelType(data[pos]);
pos += 1;
@@ -223,8 +225,9 @@ ByteVector RelativeVolumeFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h)
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new RelativeVolumeFramePrivate())
{
d = new RelativeVolumeFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -131,12 +131,12 @@ namespace TagLib {
/*!
* \deprecated Always returns master volume.
*/
ChannelType channelType() const;
TAGLIB_DEPRECATED ChannelType channelType() const;
/*!
* \deprecated This method no longer has any effect.
*/
void setChannelType(ChannelType t);
TAGLIB_DEPRECATED void setChannelType(ChannelType t);
/*
* There was a terrible API goof here, and while this can't be changed to
@@ -155,7 +155,7 @@ namespace TagLib {
* available and returns 0 if the specified channel does not exist.
*
* \see setVolumeAdjustmentIndex()
* \see volumeAjustment()
* \see volumeAdjustment()
*/
short volumeAdjustmentIndex(ChannelType type = MasterVolume) const;
@@ -167,7 +167,7 @@ namespace TagLib {
* By default this sets the value for the master volume.
*
* \see volumeAdjustmentIndex()
* \see setVolumeAjustment()
* \see setVolumeAdjustment()
*/
void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume);

View File

@@ -52,16 +52,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) :
Frame("SYLT")
Frame("SYLT"),
d(new SynchronizedLyricsFramePrivate())
{
d = new SynchronizedLyricsFramePrivate;
d->textEncoding = encoding;
}
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new SynchronizedLyricsFramePrivate())
{
d = new SynchronizedLyricsFramePrivate;
setData(data);
}
@@ -189,7 +189,7 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
}
}
String text = readStringField(data, enc, &pos);
if(text.isEmpty() || pos + 4 > end)
if(pos + 4 > end)
return;
unsigned int time = data.toUInt(pos, true);
@@ -234,9 +234,9 @@ ByteVector SynchronizedLyricsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h)
: Frame(h)
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new SynchronizedLyricsFramePrivate())
{
d = new SynchronizedLyricsFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -36,7 +36,9 @@ class TableOfContentsFrame::TableOfContentsFramePrivate
{
public:
TableOfContentsFramePrivate() :
tagHeader(0)
tagHeader(0),
isTopLevel(false),
isOrdered(false)
{
embeddedFrameList.setAutoDelete(true);
}
@@ -53,7 +55,7 @@ public:
namespace {
// These functions are needed to try to aim for backward compatibility with
// an API that previously (unreasonably) required null bytes to be appeneded
// an API that previously (unreasonably) required null bytes to be appended
// at the end of identifiers explicitly by the API user.
// BIC: remove these
@@ -73,16 +75,16 @@ namespace {
}
return l;
}
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
ID3v2::Frame(data),
d(new TableOfContentsFramePrivate())
{
d = new TableOfContentsFramePrivate;
d->tagHeader = tagHeader;
setData(data);
}
@@ -90,9 +92,9 @@ TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children,
const FrameList &embeddedFrames) :
ID3v2::Frame("CTOC")
ID3v2::Frame("CTOC"),
d(new TableOfContentsFramePrivate())
{
d = new TableOfContentsFramePrivate;
d->elementID = elementID;
strip(d->elementID);
d->childElements = children;
@@ -166,7 +168,8 @@ void TableOfContentsFrame::removeChildElement(const ByteVector &cE)
if(it == d->childElements.end())
it = d->childElements.find(cE + ByteVector("\0"));
d->childElements.erase(it);
if(it != d->childElements.end())
d->childElements.erase(it);
}
const FrameListMap &TableOfContentsFrame::embeddedFrameListMap() const
@@ -194,11 +197,14 @@ void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del)
{
// remove the frame from the frame list
FrameList::Iterator it = d->embeddedFrameList.find(frame);
d->embeddedFrameList.erase(it);
if(it != d->embeddedFrameList.end())
d->embeddedFrameList.erase(it);
// ...and from the frame list map
it = d->embeddedFrameListMap[frame->frameID()].find(frame);
d->embeddedFrameListMap[frame->frameID()].erase(it);
FrameList &mappedList = d->embeddedFrameListMap[frame->frameID()];
it = mappedList.find(frame);
if(it != mappedList.end())
mappedList.erase(it);
// ...and delete as desired
if(del)
@@ -214,7 +220,23 @@ void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
String TableOfContentsFrame::toString() const
{
return String();
String s = String(d->elementID) +
": top level: " + (d->isTopLevel ? "true" : "false") +
", ordered: " + (d->isOrdered ? "true" : "false");
if(!d->childElements.isEmpty()) {
s+= ", chapters: [ " + String(d->childElements.toByteVector(", ")) + " ]";
}
if(!d->embeddedFrameList.isEmpty()) {
StringList frameIDs;
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end(); ++it)
frameIDs.append((*it)->frameID());
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
}
return s;
}
PropertyMap TableOfContentsFrame::asProperties() const
@@ -252,7 +274,7 @@ TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag)
++it)
{
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
if(frame && frame->isTopLevel() == true)
if(frame && frame->isTopLevel())
return frame;
}
@@ -272,9 +294,9 @@ void TableOfContentsFrame::parseFields(const ByteVector &data)
int pos = 0;
unsigned int embPos = 0;
d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
d->isTopLevel = (data.at(pos) & 2) > 0;
d->isOrdered = (data.at(pos++) & 1) > 0;
unsigned int entryCount = data.at(pos++);
d->isTopLevel = (data.at(pos) & 2) != 0;
d->isOrdered = (data.at(pos++) & 1) != 0;
unsigned int entryCount = static_cast<unsigned char>(data.at(pos++));
for(unsigned int i = 0; i < entryCount; i++) {
ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
d->childElements.append(childElementID);
@@ -286,7 +308,7 @@ void TableOfContentsFrame::parseFields(const ByteVector &data)
return;
while(embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
if(!frame)
return;
@@ -314,7 +336,7 @@ ByteVector TableOfContentsFrame::renderFields() const
if(d->isOrdered)
flags += 1;
data.append(flags);
data.append((char)(entryCount()));
data.append(static_cast<char>(entryCount()));
ByteVectorList::ConstIterator it = d->childElements.begin();
while(it != d->childElements.end()) {
data.append(*it);
@@ -322,17 +344,19 @@ ByteVector TableOfContentsFrame::renderFields() const
it++;
}
FrameList l = d->embeddedFrameList;
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
(*it)->header()->setVersion(header()->version());
data.append((*it)->render());
}
return data;
}
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
const ByteVector &data, Header *h) :
Frame(h)
Frame(h),
d(new TableOfContentsFramePrivate())
{
d = new TableOfContentsFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -29,6 +29,8 @@
#include "id3v2tag.h"
#include "id3v2frame.h"
#include "tbytevectorlist.h"
namespace TagLib {
namespace ID3v2 {

View File

@@ -45,16 +45,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) :
Frame(type)
Frame(type),
d(new TextIdentificationFramePrivate())
{
d = new TextIdentificationFramePrivate;
d->textEncoding = encoding;
}
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new TextIdentificationFramePrivate())
{
d = new TextIdentificationFramePrivate;
setData(data);
}
@@ -63,7 +63,10 @@ TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const Property
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
StringList l;
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
l.append(it->first);
const String role = involvedPeopleMap()[it->first];
if(role.isEmpty()) // should not happen
continue;
l.append(role);
l.append(it->second.toString(",")); // comma-separated list of names
}
frame->setText(l);
@@ -122,22 +125,22 @@ void TextIdentificationFrame::setTextEncoding(String::Type encoding)
namespace
{
// array of allowed TIPL prefixes and their corresponding key value
const char* involvedPeople[][2] = {
{"ARRANGER", "ARRANGER"},
{"ENGINEER", "ENGINEER"},
{"PRODUCER", "PRODUCER"},
{"DJ-MIX", "DJMIXER"},
{"MIX", "MIXER"},
const std::pair<const char *, const char *> involvedPeople[] = {
std::make_pair("ARRANGER", "ARRANGER"),
std::make_pair("ENGINEER", "ENGINEER"),
std::make_pair("PRODUCER", "PRODUCER"),
std::make_pair("DJ-MIX", "DJMIXER"),
std::make_pair("MIX", "MIXER"),
};
const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]);
}
} // namespace
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
{
static KeyConversionMap m;
if(m.isEmpty()) {
for(size_t i = 0; i < involvedPeopleSize; ++i)
m.insert(involvedPeople[i][1], involvedPeople[i][0]);
m.insert(involvedPeople[i].second, involvedPeople[i].first);
}
return m;
}
@@ -215,12 +218,32 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
// append those split values to the list and make sure that the new string's
// type is the same specified for this frame
unsigned short firstBom = 0;
for(ByteVectorList::ConstIterator it = l.begin(); it != l.end(); it++) {
if(!(*it).isEmpty()) {
if(d->textEncoding == String::Latin1)
if(d->textEncoding == String::Latin1) {
d->fieldList.append(Tag::latin1StringHandler()->parse(*it));
else
d->fieldList.append(String(*it, d->textEncoding));
}
else {
String::Type textEncoding = d->textEncoding;
if(textEncoding == String::UTF16) {
if(it == l.begin()) {
firstBom = it->mid(0, 2).toUShort();
}
else {
unsigned short subsequentBom = it->mid(0, 2).toUShort();
if(subsequentBom != 0xfeff && subsequentBom != 0xfffe) {
if(firstBom == 0xfeff) {
textEncoding = String::UTF16BE;
}
else if(firstBom == 0xfffe) {
textEncoding = String::UTF16LE;
}
}
}
}
d->fieldList.append(String(*it, textEncoding));
}
}
}
}
@@ -252,9 +275,10 @@ ByteVector TextIdentificationFrame::renderFields() const
// TextIdentificationFrame private members
////////////////////////////////////////////////////////////////////////////////
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h)
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new TextIdentificationFramePrivate())
{
d = new TextIdentificationFramePrivate;
parseFields(fieldData(data));
}
@@ -270,13 +294,13 @@ PropertyMap TextIdentificationFrame::makeTIPLProperties() const
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
bool found = false;
for(size_t i = 0; i < involvedPeopleSize; ++i)
if(*it == involvedPeople[i][0]) {
map.insert(involvedPeople[i][1], (++it)->split(","));
if(*it == involvedPeople[i].first) {
map.insert(involvedPeople[i].second, (++it)->split(","));
found = true;
break;
}
if(!found){
// invalid involved role -> mark whole frame as unsupported in order to be consisten with writing
// invalid involved role -> mark whole frame as unsupported in order to be consistent with writing
map.clear();
map.unsupportedData().append(frameID());
return map;
@@ -338,7 +362,13 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const String &descripti
String UserTextIdentificationFrame::toString() const
{
return "[" + description() + "] " + fieldList().toString();
// first entry is the description itself, drop from values list
StringList l = fieldList();
for(StringList::Iterator it = l.begin(); it != l.end(); ++it) {
l.erase(it);
break;
}
return "[" + description() + "] " + l.toString();
}
String UserTextIdentificationFrame::description() const

View File

@@ -45,16 +45,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) :
ID3v2::Frame(data)
ID3v2::Frame(data),
d(new UniqueFileIdentifierFramePrivate())
{
d = new UniqueFileIdentifierFramePrivate;
setData(data);
}
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) :
ID3v2::Frame("UFID")
ID3v2::Frame("UFID"),
d(new UniqueFileIdentifierFramePrivate())
{
d = new UniqueFileIdentifierFramePrivate;
d->owner = owner;
d->identifier = id;
}
@@ -141,8 +141,8 @@ ByteVector UniqueFileIdentifierFrame::renderFields() const
}
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) :
Frame(h)
Frame(h),
d(new UniqueFileIdentifierFramePrivate())
{
d = new UniqueFileIdentifierFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -38,9 +38,10 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
UnknownFrame::UnknownFrame(const ByteVector &data) : Frame(data)
UnknownFrame::UnknownFrame(const ByteVector &data) :
Frame(data),
d(new UnknownFramePrivate())
{
d = new UnknownFramePrivate;
setData(data);
}
@@ -77,8 +78,9 @@ ByteVector UnknownFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h)
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UnknownFramePrivate())
{
d = new UnknownFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -50,16 +50,16 @@ public:
////////////////////////////////////////////////////////////////////////////////
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) :
Frame("USLT")
Frame("USLT"),
d(new UnsynchronizedLyricsFramePrivate())
{
d = new UnsynchronizedLyricsFramePrivate;
d->textEncoding = encoding;
}
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new UnsynchronizedLyricsFramePrivate())
{
d = new UnsynchronizedLyricsFramePrivate;
setData(data);
}
@@ -118,7 +118,7 @@ PropertyMap UnsynchronizedLyricsFrame::asProperties() const
{
PropertyMap map;
String key = description().upper();
if(key.isEmpty() || key.upper() == "LYRICS")
if(key.isEmpty() || key == "LYRICS")
map.insert("LYRICS", text());
else
map.insert("LYRICS:" + key, text());
@@ -190,9 +190,9 @@ ByteVector UnsynchronizedLyricsFrame::renderFields() const
// private members
////////////////////////////////////////////////////////////////////////////////
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h)
: Frame(h)
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UnsynchronizedLyricsFramePrivate())
{
d = new UnsynchronizedLyricsFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -49,10 +49,14 @@ public:
String description;
};
////////////////////////////////////////////////////////////////////////////////
// UrlLinkFrame public members
////////////////////////////////////////////////////////////////////////////////
UrlLinkFrame::UrlLinkFrame(const ByteVector &data) :
Frame(data)
Frame(data),
d(new UrlLinkFramePrivate())
{
d = new UrlLinkFramePrivate;
setData(data);
}
@@ -93,6 +97,10 @@ PropertyMap UrlLinkFrame::asProperties() const
return map;
}
////////////////////////////////////////////////////////////////////////////////
// UrlLinkFrame protected members
////////////////////////////////////////////////////////////////////////////////
void UrlLinkFrame::parseFields(const ByteVector &data)
{
d->url = String(data);
@@ -103,24 +111,28 @@ ByteVector UrlLinkFrame::renderFields() const
return d->url.data(String::Latin1);
}
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h)
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) :
Frame(h),
d(new UrlLinkFramePrivate())
{
d = new UrlLinkFramePrivate;
parseFields(fieldData(data));
}
////////////////////////////////////////////////////////////////////////////////
// UserUrlLinkFrame public members
////////////////////////////////////////////////////////////////////////////////
UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) :
UrlLinkFrame("WXXX")
UrlLinkFrame("WXXX"),
d(new UserUrlLinkFramePrivate())
{
d = new UserUrlLinkFramePrivate;
d->textEncoding = encoding;
}
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) :
UrlLinkFrame(data)
UrlLinkFrame(data),
d(new UserUrlLinkFramePrivate())
{
d = new UserUrlLinkFramePrivate;
setData(data);
}
@@ -158,7 +170,7 @@ PropertyMap UserUrlLinkFrame::asProperties() const
{
PropertyMap map;
String key = description().upper();
if(key.isEmpty() || key.upper() == "URL")
if(key.isEmpty() || key == "URL")
map.insert("URL", url());
else
map.insert("URL:" + key, url());
@@ -176,6 +188,10 @@ UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &descript
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// UserUrlLinkFrame protected members
////////////////////////////////////////////////////////////////////////////////
void UserUrlLinkFrame::parseFields(const ByteVector &data)
{
if(data.size() < 2) {
@@ -222,8 +238,9 @@ ByteVector UserUrlLinkFrame::renderFields() const
return v;
}
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h)
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) :
UrlLinkFrame(data, h),
d(new UserUrlLinkFramePrivate())
{
d = new UserUrlLinkFramePrivate;
parseFields(fieldData(data));
}

24
taglib/mpeg/id3v2/id3v2.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef TAGLIB_ID3V2_H
#define TAGLIB_ID3V2_H
namespace TagLib {
//! An ID3v2 implementation
/*!
* This is a relatively complete and flexible framework for working with ID3v2
* tags.
*
* \see ID3v2::Tag
*/
namespace ID3v2 {
/*!
* Used to specify which version of the ID3 standard to use when saving tags.
*/
enum Version {
v3 = 3, //<! ID3v2.3
v4 = 4 //<! ID3v2.4
};
}
}
#endif

View File

@@ -41,9 +41,9 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
ExtendedHeader::ExtendedHeader()
ExtendedHeader::ExtendedHeader() :
d(new ExtendedHeaderPrivate())
{
d = new ExtendedHeaderPrivate();
}
ExtendedHeader::~ExtendedHeader()

View File

@@ -38,7 +38,7 @@ namespace TagLib {
/*!
* This class implements ID3v2 extended headers. It attempts to follow,
* both semantically and programatically, the structure specified in
* both semantically and programmatically, 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.

View File

@@ -40,6 +40,7 @@
#include "frames/commentsframe.h"
#include "frames/uniquefileidentifierframe.h"
#include "frames/unknownframe.h"
#include "frames/podcastframe.h"
using namespace TagLib;
using namespace ID3v2;
@@ -73,7 +74,7 @@ namespace
}
return true;
}
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// static methods
@@ -93,8 +94,7 @@ ByteVector Frame::textDelimiter(String::Type t)
{
if(t == String::UTF16 || t == String::UTF16BE || t == String::UTF16LE)
return ByteVector(2, '\0');
else
return ByteVector(1, '\0');
return ByteVector(1, '\0');
}
const String Frame::instrumentPrefix("PERFORMER:");
@@ -111,15 +111,17 @@ Frame *Frame::createTextualFrame(const String &key, const StringList &values) //
// check if the key is contained in the key<=>frameID mapping
ByteVector frameID = keyToFrameID(key);
if(!frameID.isEmpty()) {
// Apple proprietary WFED (Podcast URL) is in fact a text frame.
if(frameID[0] == 'T' || frameID == "WFED"){ // text frame
// Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number), GRP1 (Grouping) are in fact text frames.
if(frameID[0] == 'T' || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN" || frameID == "GRP1"){ // text frame
TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8);
frame->setText(values);
return frame;
} else if((frameID[0] == 'W') && (values.size() == 1)){ // URL frame (not WXXX); support only one value
} if((frameID[0] == 'W') && (values.size() == 1)){ // URL frame (not WXXX); support only one value
UrlLinkFrame* frame = new UrlLinkFrame(frameID);
frame->setUrl(values.front());
return frame;
} if(frameID == "PCST") {
return new PodcastFrame();
}
}
if(key == "MUSICBRAINZ_TRACKID" && values.size() == 1) {
@@ -163,16 +165,14 @@ ByteVector Frame::frameID() const
{
if(d->header)
return d->header->frameID();
else
return ByteVector();
return ByteVector();
}
unsigned int Frame::size() const
{
if(d->header)
return d->header->frameSize();
else
return 0;
return 0;
}
void Frame::setData(const ByteVector &data)
@@ -198,15 +198,15 @@ ByteVector Frame::render() const
// protected members
////////////////////////////////////////////////////////////////////////////////
Frame::Frame(const ByteVector &data)
Frame::Frame(const ByteVector &data) :
d(new FramePrivate())
{
d = new FramePrivate;
d->header = new Header(data);
}
Frame::Frame(Header *h)
Frame::Frame(Header *h) :
d(new FramePrivate())
{
d = new FramePrivate;
d->header = h;
}
@@ -306,10 +306,8 @@ String::Type Frame::checkEncoding(const StringList &fields, String::Type encodin
debug("Frame::checkEncoding() -- Rendering using UTF8.");
return String::UTF8;
}
else {
debug("Frame::checkEncoding() -- Rendering using UTF16.");
return String::UTF16;
}
debug("Frame::checkEncoding() -- Rendering using UTF16.");
return String::UTF16;
}
}
@@ -323,112 +321,121 @@ String::Type Frame::checkTextEncoding(const StringList &fields, String::Type enc
namespace
{
const char *frameTranslation[][2] = {
const std::pair<const char *, const char *> frameTranslation[] = {
// Text information frames
{ "TALB", "ALBUM"},
{ "TBPM", "BPM" },
{ "TCOM", "COMPOSER" },
{ "TCON", "GENRE" },
{ "TCOP", "COPYRIGHT" },
{ "TDEN", "ENCODINGTIME" },
{ "TDLY", "PLAYLISTDELAY" },
{ "TDOR", "ORIGINALDATE" },
{ "TDRC", "DATE" },
// { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
{ "TDRL", "RELEASEDATE" },
{ "TDTG", "TAGGINGDATE" },
{ "TENC", "ENCODEDBY" },
{ "TEXT", "LYRICIST" },
{ "TFLT", "FILETYPE" },
//{ "TIPL", "INVOLVEDPEOPLE" }, handled separately
{ "TIT1", "CONTENTGROUP" },
{ "TIT2", "TITLE"},
{ "TIT3", "SUBTITLE" },
{ "TKEY", "INITIALKEY" },
{ "TLAN", "LANGUAGE" },
{ "TLEN", "LENGTH" },
//{ "TMCL", "MUSICIANCREDITS" }, handled separately
{ "TMED", "MEDIA" },
{ "TMOO", "MOOD" },
{ "TOAL", "ORIGINALALBUM" },
{ "TOFN", "ORIGINALFILENAME" },
{ "TOLY", "ORIGINALLYRICIST" },
{ "TOPE", "ORIGINALARTIST" },
{ "TOWN", "OWNER" },
{ "TPE1", "ARTIST"},
{ "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST'
{ "TPE3", "CONDUCTOR" },
{ "TPE4", "REMIXER" }, // could also be ARRANGER
{ "TPOS", "DISCNUMBER" },
{ "TPRO", "PRODUCEDNOTICE" },
{ "TPUB", "LABEL" },
{ "TRCK", "TRACKNUMBER" },
{ "TRSN", "RADIOSTATION" },
{ "TRSO", "RADIOSTATIONOWNER" },
{ "TSOA", "ALBUMSORT" },
{ "TSOP", "ARTISTSORT" },
{ "TSOT", "TITLESORT" },
{ "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes
{ "TSRC", "ISRC" },
{ "TSSE", "ENCODING" },
std::make_pair("TALB", "ALBUM"),
std::make_pair("TBPM", "BPM"),
std::make_pair("TCOM", "COMPOSER"),
std::make_pair("TCON", "GENRE"),
std::make_pair("TCOP", "COPYRIGHT"),
std::make_pair("TDEN", "ENCODINGTIME"),
std::make_pair("TDLY", "PLAYLISTDELAY"),
std::make_pair("TDOR", "ORIGINALDATE"),
std::make_pair("TDRC", "DATE"),
// std::make_pair("TRDA", "DATE"), // id3 v2.3, replaced by TDRC in v2.4
// std::make_pair("TDAT", "DATE"), // id3 v2.3, replaced by TDRC in v2.4
// std::make_pair("TYER", "DATE"), // id3 v2.3, replaced by TDRC in v2.4
// std::make_pair("TIME", "DATE"), // id3 v2.3, replaced by TDRC in v2.4
std::make_pair("TDRL", "RELEASEDATE"),
std::make_pair("TDTG", "TAGGINGDATE"),
std::make_pair("TENC", "ENCODEDBY"),
std::make_pair("TEXT", "LYRICIST"),
std::make_pair("TFLT", "FILETYPE"),
//std::make_pair("TIPL", "INVOLVEDPEOPLE"), handled separately
std::make_pair("TIT1", "WORK"), // 'Work' in iTunes
std::make_pair("TIT2", "TITLE"),
std::make_pair("TIT3", "SUBTITLE"),
std::make_pair("TKEY", "INITIALKEY"),
std::make_pair("TLAN", "LANGUAGE"),
std::make_pair("TLEN", "LENGTH"),
//std::make_pair("TMCL", "MUSICIANCREDITS"), handled separately
std::make_pair("TMED", "MEDIA"),
std::make_pair("TMOO", "MOOD"),
std::make_pair("TOAL", "ORIGINALALBUM"),
std::make_pair("TOFN", "ORIGINALFILENAME"),
std::make_pair("TOLY", "ORIGINALLYRICIST"),
std::make_pair("TOPE", "ORIGINALARTIST"),
std::make_pair("TOWN", "OWNER"),
std::make_pair("TPE1", "ARTIST"),
std::make_pair("TPE2", "ALBUMARTIST"), // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST'
std::make_pair("TPE3", "CONDUCTOR"),
std::make_pair("TPE4", "REMIXER"), // could also be ARRANGER
std::make_pair("TPOS", "DISCNUMBER"),
std::make_pair("TPRO", "PRODUCEDNOTICE"),
std::make_pair("TPUB", "LABEL"),
std::make_pair("TRCK", "TRACKNUMBER"),
std::make_pair("TRSN", "RADIOSTATION"),
std::make_pair("TRSO", "RADIOSTATIONOWNER"),
std::make_pair("TSOA", "ALBUMSORT"),
std::make_pair("TSOC", "COMPOSERSORT"),
std::make_pair("TSOP", "ARTISTSORT"),
std::make_pair("TSOT", "TITLESORT"),
std::make_pair("TSO2", "ALBUMARTISTSORT"), // non-standard, used by iTunes
std::make_pair("TSRC", "ISRC"),
std::make_pair("TSSE", "ENCODING"),
// URL frames
{ "WCOP", "COPYRIGHTURL" },
{ "WOAF", "FILEWEBPAGE" },
{ "WOAR", "ARTISTWEBPAGE" },
{ "WOAS", "AUDIOSOURCEWEBPAGE" },
{ "WORS", "RADIOSTATIONWEBPAGE" },
{ "WPAY", "PAYMENTWEBPAGE" },
{ "WPUB", "PUBLISHERWEBPAGE" },
//{ "WXXX", "URL"}, handled specially
std::make_pair("WCOP", "COPYRIGHTURL"),
std::make_pair("WOAF", "FILEWEBPAGE"),
std::make_pair("WOAR", "ARTISTWEBPAGE"),
std::make_pair("WOAS", "AUDIOSOURCEWEBPAGE"),
std::make_pair("WORS", "RADIOSTATIONWEBPAGE"),
std::make_pair("WPAY", "PAYMENTWEBPAGE"),
std::make_pair("WPUB", "PUBLISHERWEBPAGE"),
//std::make_pair("WXXX", "URL"), handled specially
// Other frames
{ "COMM", "COMMENT" },
//{ "USLT", "LYRICS" }, handled specially
std::make_pair("COMM", "COMMENT"),
//std::make_pair("USLT", "LYRICS"), handled specially
// Apple iTunes proprietary frames
{ "PCST", "PODCAST" },
{ "TCAT", "PODCASTCATEGORY" },
{ "TDES", "PODCASTDESC" },
{ "TGID", "PODCASTID" },
{ "WFED", "PODCASTURL" },
std::make_pair("PCST", "PODCAST"),
std::make_pair("TCAT", "PODCASTCATEGORY"),
std::make_pair("TDES", "PODCASTDESC"),
std::make_pair("TGID", "PODCASTID"),
std::make_pair("WFED", "PODCASTURL"),
std::make_pair("MVNM", "MOVEMENTNAME"),
std::make_pair("MVIN", "MOVEMENTNUMBER"),
std::make_pair("GRP1", "GROUPING"),
std::make_pair("TCMP", "COMPILATION"),
};
const size_t frameTranslationSize = sizeof(frameTranslation) / sizeof(frameTranslation[0]);
const char *txxxFrameTranslation[][2] = {
{ "MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID" },
{ "MUSICBRAINZ ARTIST ID", "MUSICBRAINZ_ARTISTID" },
{ "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MUSICBRAINZ RELEASE GROUP ID", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MUSICBRAINZ WORK ID", "MUSICBRAINZ_WORKID" },
{ "ACOUSTID ID", "ACOUSTID_ID" },
{ "ACOUSTID FINGERPRINT", "ACOUSTID_FINGERPRINT" },
{ "MUSICIP PUID", "MUSICIP_PUID" },
const std::pair<const char *, const char *> txxxFrameTranslation[] = {
std::make_pair("MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID"),
std::make_pair("MUSICBRAINZ ARTIST ID", "MUSICBRAINZ_ARTISTID"),
std::make_pair("MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ_ALBUMARTISTID"),
std::make_pair("MUSICBRAINZ ALBUM RELEASE COUNTRY", "RELEASECOUNTRY"),
std::make_pair("MUSICBRAINZ ALBUM STATUS", "RELEASESTATUS"),
std::make_pair("MUSICBRAINZ ALBUM TYPE", "RELEASETYPE"),
std::make_pair("MUSICBRAINZ RELEASE GROUP ID", "MUSICBRAINZ_RELEASEGROUPID"),
std::make_pair("MUSICBRAINZ RELEASE TRACK ID", "MUSICBRAINZ_RELEASETRACKID"),
std::make_pair("MUSICBRAINZ WORK ID", "MUSICBRAINZ_WORKID"),
std::make_pair("ACOUSTID ID", "ACOUSTID_ID"),
std::make_pair("ACOUSTID FINGERPRINT", "ACOUSTID_FINGERPRINT"),
std::make_pair("MUSICIP PUID", "MUSICIP_PUID"),
};
const size_t txxxFrameTranslationSize = sizeof(txxxFrameTranslation) / sizeof(txxxFrameTranslation[0]);
// list of deprecated frames and their successors
const char *deprecatedFrames[][2] = {
{"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3)
{"TDAT", "TDRC"}, // 2.3 -> 2.4
{"TYER", "TDRC"}, // 2.3 -> 2.4
{"TIME", "TDRC"}, // 2.3 -> 2.4
const std::pair<const char *, const char *> deprecatedFrames[] = {
std::make_pair("TRDA", "TDRC"), // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3)
std::make_pair("TDAT", "TDRC"), // 2.3 -> 2.4
std::make_pair("TYER", "TDRC"), // 2.3 -> 2.4
std::make_pair("TIME", "TDRC"), // 2.3 -> 2.4
};
const size_t deprecatedFramesSize = sizeof(deprecatedFrames) / sizeof(deprecatedFrames[0]);;
}
const size_t deprecatedFramesSize = sizeof(deprecatedFrames) / sizeof(deprecatedFrames[0]);
} // namespace
String Frame::frameIDToKey(const ByteVector &id)
{
ByteVector id24 = id;
for(size_t i = 0; i < deprecatedFramesSize; ++i) {
if(id24 == deprecatedFrames[i][0]) {
id24 = deprecatedFrames[i][1];
if(id24 == deprecatedFrames[i].first) {
id24 = deprecatedFrames[i].second;
break;
}
}
for(size_t i = 0; i < frameTranslationSize; ++i) {
if(id24 == frameTranslation[i][0])
return frameTranslation[i][1];
if(id24 == frameTranslation[i].first)
return frameTranslation[i].second;
}
return String();
}
@@ -437,8 +444,8 @@ ByteVector Frame::keyToFrameID(const String &s)
{
const String key = s.upper();
for(size_t i = 0; i < frameTranslationSize; ++i) {
if(key == frameTranslation[i][1])
return frameTranslation[i][0];
if(key == frameTranslation[i].second)
return frameTranslation[i].first;
}
return ByteVector();
}
@@ -447,8 +454,8 @@ String Frame::txxxToKey(const String &description)
{
const String d = description.upper();
for(size_t i = 0; i < txxxFrameTranslationSize; ++i) {
if(d == txxxFrameTranslation[i][0])
return txxxFrameTranslation[i][1];
if(d == txxxFrameTranslation[i].first)
return txxxFrameTranslation[i].second;
}
return d;
}
@@ -457,8 +464,8 @@ String Frame::keyToTXXX(const String &s)
{
const String key = s.upper();
for(size_t i = 0; i < txxxFrameTranslationSize; ++i) {
if(key == txxxFrameTranslation[i][1])
return txxxFrameTranslation[i][0];
if(key == txxxFrameTranslation[i].second)
return txxxFrameTranslation[i].first;
}
return s;
}
@@ -474,19 +481,21 @@ PropertyMap Frame::asProperties() const
// workaround until this function is virtual
if(id == "TXXX")
return dynamic_cast< const UserTextIdentificationFrame* >(this)->asProperties();
// Apple proprietary WFED (Podcast URL) is in fact a text frame.
else if(id[0] == 'T' || id == "WFED")
// Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number), GRP1 (Grouping) are in fact text frames.
if(id[0] == 'T' || id == "WFED" || id == "MVNM" || id == "MVIN" || id == "GRP1")
return dynamic_cast< const TextIdentificationFrame* >(this)->asProperties();
else if(id == "WXXX")
if(id == "WXXX")
return dynamic_cast< const UserUrlLinkFrame* >(this)->asProperties();
else if(id[0] == 'W')
if(id[0] == 'W')
return dynamic_cast< const UrlLinkFrame* >(this)->asProperties();
else if(id == "COMM")
if(id == "COMM")
return dynamic_cast< const CommentsFrame* >(this)->asProperties();
else if(id == "USLT")
if(id == "USLT")
return dynamic_cast< const UnsynchronizedLyricsFrame* >(this)->asProperties();
else if(id == "UFID")
if(id == "UFID")
return dynamic_cast< const UniqueFileIdentifierFrame* >(this)->asProperties();
if(id == "PCST")
return dynamic_cast< const PodcastFrame* >(this)->asProperties();
PropertyMap m;
m.unsupportedData().append(id);
return m;
@@ -571,15 +580,15 @@ unsigned int Frame::Header::size(unsigned int version)
// public members (Frame::Header)
////////////////////////////////////////////////////////////////////////////////
Frame::Header::Header(const ByteVector &data, bool synchSafeInts)
Frame::Header::Header(const ByteVector &data, bool synchSafeInts) :
d(new HeaderPrivate())
{
d = new HeaderPrivate;
setData(data, synchSafeInts);
}
Frame::Header::Header(const ByteVector &data, unsigned int version)
Frame::Header::Header(const ByteVector &data, unsigned int version) :
d(new HeaderPrivate())
{
d = new HeaderPrivate;
setData(data, version);
}

View File

@@ -47,7 +47,7 @@ namespace TagLib {
* 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
* gathering information about and modifying ID3v2 frames. Functionality
* specific to a given frame type is handed in one of the many subclasses.
*/
@@ -55,6 +55,8 @@ namespace TagLib {
{
friend class Tag;
friend class FrameFactory;
friend class TableOfContentsFrame;
friend class ChapterFrame;
public:
@@ -89,14 +91,15 @@ namespace TagLib {
* non-binary compatible release this will be made into a non-static
* member that checks the internal ID3v2 version.
*/
static unsigned int headerSize(); // BIC: remove and make non-static
static unsigned int headerSize(); // BIC: make non-static
/*!
* Returns the size of the frame header for the given ID3v2 version.
*
* \deprecated Please see the explanation above.
*/
static unsigned int headerSize(unsigned int version); // BIC: remove and make non-static
// BIC: remove
static unsigned int headerSize(unsigned int version);
/*!
* Sets the data that will be used as the frame. Since the length is not
@@ -224,7 +227,7 @@ namespace TagLib {
* This is useful for reading strings sequentially.
*/
String readStringField(const ByteVector &data, String::Type encoding,
int *positon = 0);
int *position = 0);
/*!
* Checks a the list of string values to see if they can be used with the
@@ -255,7 +258,7 @@ namespace TagLib {
/*!
* Parses the contents of this frame as PropertyMap. If that fails, the returend
* Parses the contents of this frame as PropertyMap. If that fails, the returned
* PropertyMap will be empty, and its unsupportedData() will contain this frame's
* ID.
* BIC: Will be a virtual function in future releases.
@@ -334,7 +337,7 @@ namespace TagLib {
* \deprecated Please use the constructor below that accepts a version
* number.
*/
Header(const ByteVector &data, bool synchSafeInts);
TAGLIB_DEPRECATED Header(const ByteVector &data, bool synchSafeInts);
/*!
* Construct a Frame Header based on \a data. \a data must at least
@@ -356,7 +359,7 @@ namespace TagLib {
* \deprecated Please use the version below that accepts an ID3v2 version
* number.
*/
void setData(const ByteVector &data, bool synchSafeInts);
TAGLIB_DEPRECATED void setData(const ByteVector &data, bool synchSafeInts);
/*!
* Sets the data for the Header. \a version should indicate the ID3v2
@@ -411,6 +414,7 @@ namespace TagLib {
* removed in the next binary incompatible release (2.0) and will be
* replaced with a non-static method that checks the frame version.
*/
// BIC: make non-static
static unsigned int size();
/*!
@@ -419,6 +423,7 @@ namespace TagLib {
*
* \deprecated Please see the explanation in the version above.
*/
// BIC: remove
static unsigned int size(unsigned int version);
/*!
@@ -500,9 +505,9 @@ namespace TagLib {
ByteVector render() const;
/*!
* \deprecated
* \deprecated Use fileAlterPreservation().
*/
bool frameAlterPreservation() const;
TAGLIB_DEPRECATED bool frameAlterPreservation() const;
private:
Header(const Header &);

View File

@@ -60,22 +60,24 @@ namespace
for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
String s = *it;
int end = s.find(")");
int offset = 0;
int end = 0;
if(s.startsWith("(") && end > 0) {
while(s.length() > offset && s[offset] == '(' &&
(end = s.find(")", offset + 1)) > offset) {
// "(12)Genre"
String text = s.substr(end + 1);
const String genreCode = s.substr(offset + 1, end - 1);
s = s.substr(end + 1);
bool ok;
int number = s.substr(1, end - 1).toInt(&ok);
if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text))
newfields.append(s.substr(1, end - 1));
if(!text.isEmpty())
newfields.append(text);
int number = genreCode.toInt(&ok);
if((ok && number >= 0 && number <= 255 &&
!(ID3v1::genre(number) == s)) ||
genreCode == "RX" || genreCode == "CR")
newfields.append(genreCode);
}
else {
if(!s.isEmpty())
// "Genre" or "12"
newfields.append(s);
}
}
if(newfields.isEmpty())
@@ -83,7 +85,7 @@ namespace
frame->setText(newfields);
}
}
} // namespace
class FrameFactory::FrameFactoryPrivate
{
@@ -126,6 +128,11 @@ Frame *FrameFactory::createFrame(const ByteVector &data, unsigned int version) c
}
Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const
{
return createFrame(origData, const_cast<const Header *>(tagHeader));
}
Frame *FrameFactory::createFrame(const ByteVector &origData, const Header *tagHeader) const
{
ByteVector data = origData;
unsigned int version = tagHeader->majorVersion();
@@ -198,8 +205,8 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
// Text Identification (frames 4.2)
// Apple proprietary WFED (Podcast URL) is in fact a text frame.
if(frameID.startsWith("T") || frameID == "WFED") {
// Apple proprietary WFED (Podcast URL), MVNM (Movement Name), MVIN (Movement Number), GRP1 (Grouping) are in fact text frames.
if(frameID.startsWith("T") || frameID == "WFED" || frameID == "MVNM" || frameID == "MVIN" || frameID == "GRP1") {
TextIdentificationFrame *f = frameID != "TXXX"
? new TextIdentificationFrame(data, header)
@@ -261,11 +268,9 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
if(frameID != "WXXX") {
return new UrlLinkFrame(data, header);
}
else {
UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header);
d->setTextEncoding(f);
return f;
}
UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header);
d->setTextEncoding(f);
return f;
}
// Unsynchronized lyric/text transcription (frames 4.8)
@@ -277,7 +282,7 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
return f;
}
// Synchronised lyrics/text (frames 4.9)
// Synchronized lyrics/text (frames 4.9)
if(frameID == "SYLT") {
SynchronizedLyricsFrame *f = new SynchronizedLyricsFrame(data, header);
@@ -334,19 +339,21 @@ void FrameFactory::rebuildAggregateFrames(ID3v2::Tag *tag) const
tag->frameList("TDAT").size() == 1)
{
TextIdentificationFrame *tdrc =
static_cast<TextIdentificationFrame *>(tag->frameList("TDRC").front());
UnknownFrame *tdat = static_cast<UnknownFrame *>(tag->frameList("TDAT").front());
dynamic_cast<TextIdentificationFrame *>(tag->frameList("TDRC").front());
UnknownFrame *tdat = dynamic_cast<UnknownFrame *>(tag->frameList("TDAT").front());
if(tdrc->fieldList().size() == 1 &&
if(tdrc &&
tdrc->fieldList().size() == 1 &&
tdrc->fieldList().front().size() == 4 &&
tdat &&
tdat->data().size() >= 5)
{
String date(tdat->data().mid(1), String::Type(tdat->data()[0]));
if(date.length() == 4) {
tdrc->setText(tdrc->toString() + '-' + date.substr(2, 2) + '-' + date.substr(0, 2));
if(tag->frameList("TIME").size() == 1) {
UnknownFrame *timeframe = static_cast<UnknownFrame *>(tag->frameList("TIME").front());
if(timeframe->data().size() >= 5) {
UnknownFrame *timeframe = dynamic_cast<UnknownFrame *>(tag->frameList("TIME").front());
if(timeframe && timeframe->data().size() >= 5) {
String time(timeframe->data().mid(1), String::Type(timeframe->data()[0]));
if(time.length() == 4) {
tdrc->setText(tdrc->toString() + 'T' + time.substr(0, 2) + ':' + time.substr(2, 2));
@@ -386,87 +393,90 @@ FrameFactory::~FrameFactory()
namespace
{
// Frame conversion table ID3v2.2 -> 2.4
const char *frameConversion2[][2] = {
{ "BUF", "RBUF" },
{ "CNT", "PCNT" },
{ "COM", "COMM" },
{ "CRA", "AENC" },
{ "ETC", "ETCO" },
{ "GEO", "GEOB" },
{ "IPL", "TIPL" },
{ "MCI", "MCDI" },
{ "MLL", "MLLT" },
{ "POP", "POPM" },
{ "REV", "RVRB" },
{ "SLT", "SYLT" },
{ "STC", "SYTC" },
{ "TAL", "TALB" },
{ "TBP", "TBPM" },
{ "TCM", "TCOM" },
{ "TCO", "TCON" },
{ "TCP", "TCMP" },
{ "TCR", "TCOP" },
{ "TDY", "TDLY" },
{ "TEN", "TENC" },
{ "TFT", "TFLT" },
{ "TKE", "TKEY" },
{ "TLA", "TLAN" },
{ "TLE", "TLEN" },
{ "TMT", "TMED" },
{ "TOA", "TOAL" },
{ "TOF", "TOFN" },
{ "TOL", "TOLY" },
{ "TOR", "TDOR" },
{ "TOT", "TOAL" },
{ "TP1", "TPE1" },
{ "TP2", "TPE2" },
{ "TP3", "TPE3" },
{ "TP4", "TPE4" },
{ "TPA", "TPOS" },
{ "TPB", "TPUB" },
{ "TRC", "TSRC" },
{ "TRD", "TDRC" },
{ "TRK", "TRCK" },
{ "TS2", "TSO2" },
{ "TSA", "TSOA" },
{ "TSC", "TSOC" },
{ "TSP", "TSOP" },
{ "TSS", "TSSE" },
{ "TST", "TSOT" },
{ "TT1", "TIT1" },
{ "TT2", "TIT2" },
{ "TT3", "TIT3" },
{ "TXT", "TOLY" },
{ "TXX", "TXXX" },
{ "TYE", "TDRC" },
{ "UFI", "UFID" },
{ "ULT", "USLT" },
{ "WAF", "WOAF" },
{ "WAR", "WOAR" },
{ "WAS", "WOAS" },
{ "WCM", "WCOM" },
{ "WCP", "WCOP" },
{ "WPB", "WPUB" },
{ "WXX", "WXXX" },
const std::pair<const char *, const char *> frameConversion2[] = {
std::make_pair("BUF", "RBUF"),
std::make_pair("CNT", "PCNT"),
std::make_pair("COM", "COMM"),
std::make_pair("CRA", "AENC"),
std::make_pair("ETC", "ETCO"),
std::make_pair("GEO", "GEOB"),
std::make_pair("IPL", "TIPL"),
std::make_pair("MCI", "MCDI"),
std::make_pair("MLL", "MLLT"),
std::make_pair("POP", "POPM"),
std::make_pair("REV", "RVRB"),
std::make_pair("SLT", "SYLT"),
std::make_pair("STC", "SYTC"),
std::make_pair("TAL", "TALB"),
std::make_pair("TBP", "TBPM"),
std::make_pair("TCM", "TCOM"),
std::make_pair("TCO", "TCON"),
std::make_pair("TCP", "TCMP"),
std::make_pair("TCR", "TCOP"),
std::make_pair("TDY", "TDLY"),
std::make_pair("TEN", "TENC"),
std::make_pair("TFT", "TFLT"),
std::make_pair("TKE", "TKEY"),
std::make_pair("TLA", "TLAN"),
std::make_pair("TLE", "TLEN"),
std::make_pair("TMT", "TMED"),
std::make_pair("TOA", "TOAL"),
std::make_pair("TOF", "TOFN"),
std::make_pair("TOL", "TOLY"),
std::make_pair("TOR", "TDOR"),
std::make_pair("TOT", "TOAL"),
std::make_pair("TP1", "TPE1"),
std::make_pair("TP2", "TPE2"),
std::make_pair("TP3", "TPE3"),
std::make_pair("TP4", "TPE4"),
std::make_pair("TPA", "TPOS"),
std::make_pair("TPB", "TPUB"),
std::make_pair("TRC", "TSRC"),
std::make_pair("TRD", "TDRC"),
std::make_pair("TRK", "TRCK"),
std::make_pair("TS2", "TSO2"),
std::make_pair("TSA", "TSOA"),
std::make_pair("TSC", "TSOC"),
std::make_pair("TSP", "TSOP"),
std::make_pair("TSS", "TSSE"),
std::make_pair("TST", "TSOT"),
std::make_pair("TT1", "TIT1"),
std::make_pair("TT2", "TIT2"),
std::make_pair("TT3", "TIT3"),
std::make_pair("TXT", "TOLY"),
std::make_pair("TXX", "TXXX"),
std::make_pair("TYE", "TDRC"),
std::make_pair("UFI", "UFID"),
std::make_pair("ULT", "USLT"),
std::make_pair("WAF", "WOAF"),
std::make_pair("WAR", "WOAR"),
std::make_pair("WAS", "WOAS"),
std::make_pair("WCM", "WCOM"),
std::make_pair("WCP", "WCOP"),
std::make_pair("WPB", "WPUB"),
std::make_pair("WXX", "WXXX"),
// Apple iTunes nonstandard frames
{ "PCS", "PCST" },
{ "TCT", "TCAT" },
{ "TDR", "TDRL" },
{ "TDS", "TDES" },
{ "TID", "TGID" },
{ "WFD", "WFED" },
std::make_pair("PCS", "PCST"),
std::make_pair("TCT", "TCAT"),
std::make_pair("TDR", "TDRL"),
std::make_pair("TDS", "TDES"),
std::make_pair("TID", "TGID"),
std::make_pair("WFD", "WFED"),
std::make_pair("MVN", "MVNM"),
std::make_pair("MVI", "MVIN"),
std::make_pair("GP1", "GRP1"),
};
const size_t frameConversion2Size = sizeof(frameConversion2) / sizeof(frameConversion2[0]);
// Frame conversion table ID3v2.3 -> 2.4
const char *frameConversion3[][2] = {
{ "TORY", "TDOR" },
{ "TYER", "TDRC" },
{ "IPLS", "TIPL" },
const std::pair<const char *, const char *> frameConversion3[] = {
std::make_pair("TORY", "TDOR"),
std::make_pair("TYER", "TDRC"),
std::make_pair("IPLS", "TIPL"),
};
const size_t frameConversion3Size = sizeof(frameConversion3) / sizeof(frameConversion3[0]);
}
} // namespace
bool FrameFactory::updateFrame(Frame::Header *header) const
{
@@ -493,8 +503,8 @@ bool FrameFactory::updateFrame(Frame::Header *header) const
// the frames to their 4 byte ID3v2.4 equivalent.
for(size_t i = 0; i < frameConversion2Size; ++i) {
if(frameID == frameConversion2[i][0]) {
header->setFrameID(frameConversion2[i][1]);
if(frameID == frameConversion2[i].first) {
header->setFrameID(frameConversion2[i].second);
break;
}
}
@@ -517,8 +527,8 @@ bool FrameFactory::updateFrame(Frame::Header *header) const
}
for(size_t i = 0; i < frameConversion3Size; ++i) {
if(frameID == frameConversion3[i][0]) {
header->setFrameID(frameConversion3[i][1]);
if(frameID == frameConversion3[i].first) {
header->setFrameID(frameConversion3[i].second);
break;
}
}

Some files were not shown because too many files have changed in this diff Show More