379 Commits

Author SHA1 Message Date
Tim Malseed
65a6a4e225 Minor fix for mp4 media header v0 minimum size check (#894)
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:08 -05:00
Tim Malseed
02090f335d Fixed an MP4 AudioProperties parsing error (#892)
The 'unit' (timescale) of 'mdhd' v1 atoms is a 32-bit unsigned integer (4 bytes long), but is parsed as a 64-bit integer (8 bytes long). This also affects the byte offset of the 'length' (duration).  This results in MP4 AudioProperties reporting a track length of zero.

This change addresses both problems.

See:
https://wiki.multimedia.cx/index.php/QuickTime_container
2019-03-16 07:59:13 -05:00
Stephen F. Booth
96a4d896ba Merge branch 'sandsmark-taglib2' into taglib2 2018-10-29 18:16:12 -05:00
Stephen F. Booth
15163b7af2 Resolved merge conflicts 2018-10-29 18:15:50 -05:00
Stephen F. Booth
19ee7c86c4 Merge branch 'master' into taglib2 2018-10-28 10:53:23 -05:00
evpobr
fc31a09c03 Fix undefined PLATFORM_WINRT CMake option (#870) 2018-10-09 18:52:09 -05:00
Alberto Fustinoni
2052cda5fb Added setProperties implementation to TagUnion (#813)
Added setProperties support in TagUnion
2018-08-24 08:40:15 -05:00
Tsuda Kageyu
6048cdef3e Apply smart pointers to MPC::File. 2017-06-14 10:11:37 +09:00
Tsuda Kageyu
ff34e42aef Apply smart pointers to FLAC::File. 2017-06-14 10:09:11 +09:00
Tsuda Kageyu
bac14180e9 Apply smart pointers to DSF::File. 2017-06-14 09:51:38 +09:00
Tsuda Kageyu
c30bae9b00 Apply smart pointers to RIFF related classes. 2017-06-14 09:47:38 +09:00
Tsuda Kageyu
4dcdaaf92a Apply smart pointers to ASF::File. 2017-06-14 09:37:31 +09:00
Tsuda Kageyu
507f1a96a7 Merge branch 'master' into taglib2
# Conflicts:
#	taglib/audioproperties.cpp
2017-06-14 09:15:06 +09:00
Tsuda Kageyu
81945efdff Move deprecated functions setID3v2FrameFactory(). 2017-06-13 09:40:01 +09:00
Tsuda Kageyu
2075d865cd Move deprecated function ByteVector::checksum() to oggpage.cpp.
ByteVector::checksum() was specially designed for Ogg pages.
So it should belong to Ogg rather than ByteVector.
2017-06-13 09:31:30 +09:00
Tsuda Kageyu
89f06af3f7 Remove a deprecated function FileRef::create(). 2017-06-12 17:27:08 +09:00
Tsuda Kageyu
3ae0d4aa90 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/fileref.cpp
#	taglib/fileref.h
#	taglib/mpeg/mpegheader.cpp
#	taglib/tagutils.h
2017-06-12 17:23:44 +09:00
Tsuda Kageyu
7e9f019a49 Remove optional dependencies on Boost.
Standard smart pointers are now common among the latest compilers.
2017-06-09 11:31:22 +09:00
Tsuda Kageyu
10e8866fec Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	ConfigureChecks.cmake
#	taglib/CMakeLists.txt
#	taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
#	taglib/toolkit/tfilestream.cpp
2017-06-09 11:11:44 +09:00
Tsuda Kageyu
bd4a45b07e Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	ConfigureChecks.cmake
#	taglib/CMakeLists.txt
#	taglib/asf/asfattribute.cpp
#	taglib/it/itproperties.cpp
#	taglib/mod/modproperties.cpp
#	taglib/mpeg/mpegfile.cpp
#	taglib/mpeg/mpegproperties.cpp
#	taglib/ogg/flac/oggflacfile.cpp
#	taglib/s3m/s3mproperties.cpp
#	taglib/tagunion.cpp
#	taglib/toolkit/tfile.cpp
#	taglib/toolkit/trefcounter.h
#	taglib/toolkit/tstring.cpp
#	taglib/xm/xmproperties.cpp
#	tests/test_mpeg.cpp
2017-02-21 10:22:20 +09:00
Tsuda Kageyu
4328f934c8 Merge pull request #781 from claudiuslollarius/taglib2
Fixed incorrect handling of MP4 tags when using wstrings
2017-01-28 22:04:25 +09:00
Tsuda Kageyu
1c20f92a8f Use smart pointers in APE related classes. 2016-12-16 14:42:16 +09:00
Tsuda Kageyu
d8114059ee Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	config.h.cmake
#	taglib/ogg/xiphcomment.cpp
#	taglib/taglib_config.h.cmake
#	taglib/toolkit/tbytevector.cpp
#	taglib/toolkit/trefcounter.cpp
#	taglib/toolkit/tstring.cpp
#	taglib/toolkit/tutils.h
#	taglib/toolkit/tzlib.cpp
#	taglib/xm/xmfile.cpp
#	tests/test_string.cpp
#	tests/test_xiphcomment.cpp
2016-12-13 13:52:35 +09:00
Tsuda Kageyu
eea1a1b200 Allow implicit conversions from const char * or const wchar_t * to FileName in Win32. 2016-12-13 13:32:38 +09:00
Tsuda Kageyu
ef1ae1a8fe Merge pull request #785 from mathbunnyru/add_explicit_keyboard
Add explicit keyword wherever easily possible
2016-12-12 13:56:09 +09:00
mathbunnyru
7eab1bf6df Add explicit keyword wherever easily possible 2016-12-10 15:44:38 +03:00
Alberto Fustinoni
6a2e276767 Formatting 2016-11-28 16:34:01 +09:00
Alberto Fustinoni
e188a39b5c Spacing 2016-11-28 16:33:21 +09:00
Alberto Fustinoni
e77e20597d Nothing in this file requires config.h directives, and it causes compilation to fail when not using one (HAVE_CONFIG_H not set) 2016-11-28 16:30:24 +09:00
Alberto Fustinoni
0b9a2df3ec Fixed incorrect handling of wstring mime types when setting pictures 2016-11-28 16:24:22 +09:00
Tsuda Kageyu
bd5688ae5f Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/mp4/mp4atom.cpp
#	taglib/toolkit/tutils.h
#	tests/test_apetag.cpp
2016-11-09 11:05:53 +09:00
Tsuda Kageyu
13223ad497 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/mp4/mp4atom.cpp
#	taglib/toolkit/tlist.tcc
#	taglib/toolkit/tmap.tcc
#	tests/test_asf.cpp
#	tests/test_ogg.cpp
#	tests/test_oggflac.cpp
#	tests/test_opus.cpp
#	tests/test_speex.cpp
2016-11-04 17:18:59 +09:00
Tsuda Kageyu
5c8cb9b86b Small fix in a comment. 2016-11-03 09:52:20 +09:00
Tsuda Kageyu
3a6f0d46aa Use a smart pointer in TagLib::Picture. 2016-11-01 11:47:37 +09:00
Tsuda Kageyu
ef6d76889b Add a missing copyright header. 2016-11-01 11:13:44 +09:00
Tsuda Kageyu
28470221c0 Suppress MSVC warnings about narrowing conversions. 2016-10-31 01:03:33 +09:00
Tsuda Kageyu
f355110d18 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/toolkit/tbytevector.cpp
#	taglib/toolkit/tfilestream.cpp
#	taglib/toolkit/tiostream.cpp
#	taglib/toolkit/tstring.cpp
2016-10-31 00:37:20 +09:00
Tsuda Kageyu
921a68ae55 Fix mismatched types in tests. 2016-10-30 21:29:06 +09:00
Tsuda Kageyu
d9df59306f Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	AUTHORS
#	ConfigureChecks.cmake
#	taglib/asf/asfutils.h
#	taglib/mp4/mp4atom.cpp
#	taglib/mp4/mp4tag.h
#	taglib/mpeg/id3v2/frames/ownershipframe.cpp
#	taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
#	taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
#	taglib/mpeg/id3v2/id3v2frame.cpp
#	taglib/riff/rifffile.cpp
#	taglib/riff/rifffile.h
#	taglib/toolkit/taglib.h
#	taglib/toolkit/tbytevector.cpp
#	taglib/toolkit/tfilestream.cpp
#	taglib/toolkit/tstring.cpp
#	taglib/toolkit/tutils.h
#	taglib/xm/xmfile.cpp
#	tests/test_bytevector.cpp
#	tests/test_fileref.cpp
#	tests/test_id3v2.cpp
#	tests/test_riff.cpp
#	tests/test_string.cpp
2016-10-30 21:20:23 +09:00
Tsuda Kageyu
fea7e3d4a2 Suppress an MSVC warning about 32bit and 64bit shift. 2016-10-28 14:46:48 +09:00
Tsuda Kageyu
b6d21ce890 Remove redundant if blocks from RIFF::File. 2016-10-28 14:42:32 +09:00
Scott Wheeler
51b85abc0b foo 2016-09-14 19:55:55 +03:00
Scott Wheeler
9452970528 No reason to include std::string here 2016-09-14 19:54:16 +03:00
Scott Wheeler
53ac43b5f6 This should be using operator| not operator||
This is bitwise, not logical.
2016-09-14 19:53:46 +03:00
Stephen F. Booth
a64772a832 Merge pull request #748 from supermihi/taglib2
Adds a function for dynamic version information retrieval
2016-08-14 17:10:04 -04:00
Michael Helmling
c352425ee7 Adjust version macros to TagLib naming conventions; use dedicated namespace 2016-07-30 13:47:46 +02:00
Michael Helmling
0f096af504 Extend dynamic version retrieval; remove C++11 dependency 2016-07-28 22:32:44 +02:00
Michael Helmling
a16c95b33f Adds a function for dynamic version information retrieval
The current way of exposing TagLib's version only through #define's
makes it impossible for clients (e.g. language bindings) to reliably
determine the TagLib version that is currently in use: using the
define's in client code will statically copy the compile-time values
into the client's library, but if TagLib is dynamically bound the
version (at least minor and patch version) can change after building
client code.
2016-07-23 13:08:23 +02:00
Scott Wheeler
821ff14a43 Put a to-do note in here to look at before actually releasing this API 2016-04-24 21:54:28 +02:00
Tsuda Kageyu
33c0ece830 Fix type mismatch errors in test_apetag.cpp. 2016-02-04 20:54:43 +09:00
Tsuda Kageyu
57e849b0d5 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/ape/apeitem.cpp
#	taglib/mpeg/mpegheader.cpp
#	taglib/toolkit/tutils.h
2016-02-04 20:48:31 +09:00
Tsuda Kageyu
b972f24193 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/ogg/oggfile.cpp
2016-01-07 09:01:32 +09:00
Tsuda Kageyu
1a73c82a76 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/flac/flacfile.h
#	taglib/mpeg/mpegheader.cpp
#	taglib/mpeg/mpegproperties.cpp
#	taglib/ogg/oggfile.cpp
#	taglib/ogg/oggpage.cpp
#	taglib/ogg/oggpageheader.cpp
#	tests/test_mpeg.cpp
2016-01-06 10:28:09 +09:00
Tsuda Kageyu
c3c862e911 Merge branch 'taglib2' of https://github.com/taglib/taglib into taglib2 2015-12-21 16:17:34 +09:00
Tsuda Kageyu
75159614fc Silence MSVC warnings concerning narrowing conversions. 2015-12-21 15:17:59 +09:00
Tsuda Kageyu
ed0305bd3f Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/ape/apefile.cpp
#	taglib/flac/flacfile.cpp
#	taglib/mpc/mpcfile.cpp
#	taglib/mpeg/mpegfile.cpp
#	taglib/mpeg/mpegfile.h
#	taglib/trueaudio/trueaudiofile.cpp
#	taglib/wavpack/wavpackfile.cpp
2015-12-21 14:56:13 +09:00
Tsuda Kageyu
f72b0ecebf Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	CMakeLists.txt
#	ConfigureChecks.cmake
#	taglib/flac/flacfile.cpp
#	taglib/mp4/mp4file.cpp
#	taglib/mpeg/mpegheader.cpp
#	taglib/mpeg/mpegproperties.cpp
#	taglib/riff/rifffile.cpp
#	taglib/toolkit/trefcounter.h
2015-12-16 13:33:04 +09:00
Tsuda Kageyu
f25a54a177 Merge pull request #696 from FestusHagen/fh1.t2_IntegerConstantTooLargeForLong
Silence error: Integer constant is too large for long type.
2015-12-06 07:12:53 +09:00
Festus Hagen
ff94a6e4a0 Silence error: Integer constant is too large for long type. 2015-12-05 11:41:00 -05:00
Tsuda Kageyu
1f5ed5fb28 Remove custom integer types. 2015-12-03 15:11:09 +09:00
Tsuda Kageyu
0e4f9f4e94 Fix a compilation error caused on the merge. 2015-12-03 14:48:21 +09:00
Tsuda Kageyu
6857926da2 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/ape/apefile.cpp
#	taglib/ape/apeitem.cpp
#	taglib/ape/apeproperties.cpp
#	taglib/ape/apetag.cpp
#	taglib/ape/apetag.h
#	taglib/asf/asffile.cpp
#	taglib/asf/asfpicture.cpp
#	taglib/flac/flacfile.cpp
#	taglib/flac/flacpicture.cpp
#	taglib/flac/flacproperties.cpp
#	taglib/it/itfile.cpp
#	taglib/it/itproperties.cpp
#	taglib/mod/modfile.cpp
#	taglib/mod/modfilebase.cpp
#	taglib/mod/modfilebase.h
#	taglib/mod/modfileprivate.h
#	taglib/mod/modproperties.cpp
#	taglib/mp4/mp4item.cpp
#	taglib/mp4/mp4tag.cpp
#	taglib/mp4/mp4tag.h
#	taglib/mpc/mpcfile.cpp
#	taglib/mpc/mpcproperties.cpp
#	taglib/mpc/mpcproperties.h
#	taglib/mpeg/id3v1/id3v1tag.cpp
#	taglib/mpeg/id3v1/id3v1tag.h
#	taglib/mpeg/id3v2/frames/attachedpictureframe.cpp
#	taglib/mpeg/id3v2/frames/chapterframe.cpp
#	taglib/mpeg/id3v2/frames/eventtimingcodesframe.cpp
#	taglib/mpeg/id3v2/frames/popularimeterframe.cpp
#	taglib/mpeg/id3v2/frames/relativevolumeframe.cpp
#	taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
#	taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
#	taglib/mpeg/id3v2/frames/textidentificationframe.cpp
#	taglib/mpeg/id3v2/id3v2frame.cpp
#	taglib/mpeg/id3v2/id3v2framefactory.cpp
#	taglib/mpeg/id3v2/id3v2framefactory.h
#	taglib/mpeg/id3v2/id3v2tag.cpp
#	taglib/mpeg/id3v2/id3v2tag.h
#	taglib/mpeg/mpegfile.cpp
#	taglib/mpeg/mpegheader.cpp
#	taglib/ogg/flac/oggflacfile.cpp
#	taglib/ogg/opus/opusproperties.cpp
#	taglib/ogg/speex/speexproperties.cpp
#	taglib/ogg/vorbis/vorbisproperties.cpp
#	taglib/ogg/xiphcomment.cpp
#	taglib/ogg/xiphcomment.h
#	taglib/riff/aiff/aiffproperties.cpp
#	taglib/riff/rifffile.cpp
#	taglib/riff/rifffile.h
#	taglib/riff/wav/infotag.cpp
#	taglib/riff/wav/infotag.h
#	taglib/riff/wav/wavproperties.cpp
#	taglib/riff/wav/wavproperties.h
#	taglib/s3m/s3mproperties.cpp
#	taglib/tagunion.cpp
#	taglib/tagunion.h
#	taglib/toolkit/taglib.h
#	taglib/toolkit/tbytevector.cpp
#	taglib/toolkit/tbytevector.h
#	taglib/toolkit/tbytevectorlist.cpp
#	taglib/toolkit/tbytevectorstream.cpp
#	taglib/toolkit/tbytevectorstream.h
#	taglib/toolkit/tfile.cpp
#	taglib/toolkit/tfile.h
#	taglib/toolkit/tfilestream.cpp
#	taglib/toolkit/tfilestream.h
#	taglib/toolkit/tiostream.h
#	taglib/toolkit/tlist.h
#	taglib/toolkit/tlist.tcc
#	taglib/toolkit/tmap.h
#	taglib/toolkit/tmap.tcc
#	taglib/toolkit/tstring.cpp
#	taglib/toolkit/tstring.h
#	taglib/trueaudio/trueaudiofile.cpp
#	taglib/trueaudio/trueaudioproperties.cpp
#	taglib/trueaudio/trueaudioproperties.h
#	taglib/wavpack/wavpackfile.cpp
#	taglib/wavpack/wavpackproperties.cpp
#	taglib/wavpack/wavpackproperties.h
#	taglib/xm/xmfile.cpp
#	taglib/xm/xmproperties.cpp
#	tests/test_apetag.cpp
#	tests/test_asf.cpp
#	tests/test_bytevector.cpp
#	tests/test_bytevectorlist.cpp
#	tests/test_file.cpp
#	tests/test_flac.cpp
#	tests/test_flacpicture.cpp
#	tests/test_id3v2.cpp
#	tests/test_info.cpp
#	tests/test_mp4.cpp
#	tests/test_ogg.cpp
#	tests/test_riff.cpp
#	tests/test_string.cpp
#	tests/test_xiphcomment.cpp
2015-12-03 14:44:17 +09:00
Tsuda Kageyu
afa137e1c1 Fix some mistakes on merging. 2015-12-02 09:37:18 +09:00
Tsuda Kageyu
d36550f96d Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/ape/apetag.cpp
#	taglib/ape/apetag.h
#	taglib/flac/flacproperties.cpp
#	taglib/mpeg/id3v1/id3v1tag.cpp
#	taglib/mpeg/id3v2/id3v2tag.cpp
#	taglib/riff/rifffile.cpp
#	taglib/riff/wav/infotag.cpp
#	taglib/toolkit/tbytevector.cpp
2015-12-02 09:31:10 +09:00
Tsuda Kageyu
6f5874a035 Remove the definition of offset_t.
The definition of offset_t has changed over time, and it's just equivalent to long long now.
We no longer have a good reason to keep it.
2015-12-01 22:10:24 +09:00
Tsuda Kageyu
2f29f0e1d0 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	CMakeLists.txt
#	examples/CMakeLists.txt
#	tests/test_asf.cpp
#	tests/test_fileref.cpp
#	tests/test_flac.cpp
#	tests/test_mp4.cpp
#	tests/test_ogg.cpp
#	tests/test_oggflac.cpp
#	tests/test_riff.cpp
2015-11-30 11:25:32 +09:00
Tsuda Kageyu
7baa7e70fe Silence GCC warnings about uninitialized variables. 2015-11-23 23:24:17 +09:00
Tsuda Kageyu
faca7ac8f4 Merge branch 'master' into merge-master-to-talib2
# Conflicts:
#	taglib/asf/asfattribute.cpp
#	taglib/asf/asfpicture.cpp
#	taglib/mp4/mp4coverart.cpp
#	taglib/mp4/mp4item.cpp
#	taglib/mp4/mp4item.h
#	taglib/mpeg/id3v2/id3v2framefactory.cpp
#	taglib/toolkit/tstring.cpp
#	tests/test_string.cpp
2015-11-23 19:04:06 +09:00
Tsuda Kageyu
1063110701 Silence some MSVC warnings about signed/unsigned mismatches. 2015-11-22 17:57:37 +09:00
Tsuda Kageyu
973fb49cde Remove obsolete String::null and related functions. 2015-11-22 17:56:18 +09:00
Tsuda Kageyu
15775d4135 Merge branch 'master' into taglib2 2015-11-22 16:25:34 +09:00
Tsuda Kageyu
52774d66ab Merge pull request #660 from MaxLeb/ASF
ASF: Adds support for pictures
2015-11-22 16:11:05 +09:00
Tsuda Kageyu
b7e3ff8cb5 Merge pull request #659 from MaxLeb/MP4
MP4: Full support of pictures
2015-11-22 16:10:53 +09:00
Tsuda Kageyu
b4a33b0306 Merge pull request #658 from MaxLeb/APE
APE: Adds support for pictures
2015-11-22 16:10:15 +09:00
Tsuda Kageyu
aa9e5c3c2f Merge pull request #657 from MaxLeb/ID3V2
ID3V2: Adds support for pictures
2015-11-22 16:10:05 +09:00
Tsuda Kageyu
0556b6ca33 Merge branch 'Examples' of https://github.com/MaxLeb/taglib into MaxLeb-Examples
# Conflicts:
#	examples/tagwriter.cpp
2015-11-22 16:05:56 +09:00
Tsuda Kageyu
b3014f0878 Merge branch 'pictures' of https://github.com/MaxLeb/taglib into MaxLeb-pictures
# Conflicts:
#	taglib/mpeg/id3v2/id3v2tag.cpp
#	taglib/tagunion.cpp
2015-11-22 15:46:22 +09:00
Tsuda Kageyu
6566352728 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/ape/apefile.cpp
#	taglib/ape/apefile.h
#	taglib/fileref.cpp
#	taglib/flac/flacfile.cpp
#	taglib/flac/flacfile.h
#	taglib/mpc/mpcfile.cpp
#	taglib/mpc/mpcfile.h
#	taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
#	taglib/mpeg/id3v2/id3v2frame.cpp
#	taglib/tagunion.cpp
#	taglib/toolkit/tiostream.cpp
#	taglib/trueaudio/trueaudiofile.cpp
#	taglib/trueaudio/trueaudiofile.h
#	taglib/wavpack/wavpackfile.cpp
#	taglib/wavpack/wavpackfile.h
#	tests/test_fileref.cpp
#	tests/test_id3v2.cpp
2015-11-21 20:22:07 +09:00
Tsuda Kageyu
1d0552cab1 Change String::npos from a variable to a function.
We can't export a static member function. It may lead to a linkage error.
2015-11-20 16:46:02 +09:00
Tsuda Kageyu
bb49005267 Fix a mismatch between the CMake check and the actual code. 2015-11-20 15:28:38 +09:00
Tsuda Kageyu
47cb23d738 Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	taglib/ape/apefile.cpp
#	taglib/asf/asffile.cpp
#	taglib/asf/asftag.cpp
#	taglib/flac/flacfile.cpp
#	taglib/mp4/mp4tag.cpp
#	taglib/mpc/mpcfile.cpp
#	taglib/mpeg/mpegfile.cpp
#	taglib/mpeg/mpegfile.h
#	taglib/riff/wav/wavfile.cpp
#	taglib/tagunion.cpp
#	taglib/tagunion.h
#	taglib/trueaudio/trueaudiofile.cpp
#	taglib/wavpack/wavpackfile.cpp
2015-11-20 15:17:39 +09:00
Tsuda Kageyu
d37c081cda Fix compilation errors on Clang. 2015-11-19 14:20:51 +09:00
Tsuda Kageyu
dbe3a03b62 Hide string handler implementations from public headers. 2015-11-19 14:08:40 +09:00
Tsuda Kageyu
5da35f5a51 Rename RIFF::Info::FieldListMap to FieldMap.
It doesn't contain string lists.
2015-11-19 13:47:41 +09:00
Tsuda Kageyu
176e133f32 Change ByteVector::npos from a variable to a function.
We can't export a static member function. It may lead to a likage error.
2015-11-19 13:13:15 +09:00
Tsuda Kageyu
722f317f97 Remove ByteVector::null and isNull(). 2015-11-19 11:57:30 +09:00
Tsuda Kageyu
c2753f8d3c Merge branch 'master' into merge-master-to-taglib2
# Conflicts:
#	ConfigureChecks.cmake
#	bindings/c/tag_c.cpp
#	taglib-config.cmd.cmake
#	taglib/asf/asfattribute.cpp
#	taglib/asf/asffile.cpp
#	taglib/audioproperties.cpp
#	taglib/mp4/mp4atom.h
#	taglib/mp4/mp4coverart.cpp
#	taglib/mp4/mp4file.cpp
#	taglib/mp4/mp4item.cpp
#	taglib/mp4/mp4tag.cpp
#	taglib/mpeg/id3v2/id3v2frame.cpp
#	taglib/mpeg/id3v2/id3v2tag.cpp
#	taglib/toolkit/tbytevector.cpp
#	taglib/toolkit/tbytevector.h
#	taglib/toolkit/tfile.cpp
#	taglib/toolkit/tfile.h
#	taglib/toolkit/tlist.h
#	taglib/toolkit/tstring.cpp
#	taglib/toolkit/tstring.h
#	tests/test_apetag.cpp
2015-11-19 11:37:18 +09:00
Tsuda Kageyu
da7424636b Fix a mismatch between List and iterator types. 2015-11-18 17:50:48 +09:00
Tsuda Kageyu
0b2a3ce400 Remove const from the key type of APE::ItemListMap.
A key type must be copy-assignable, and some compilers check it strictly.
2015-11-18 17:27:25 +09:00
Tsuda Kageyu
1ff30e55da Revert "Stop exporting std::string and std::wstring in a public header."
This reverts commit 0e981adcc6.
2015-09-11 19:59:20 +09:00
Tsuda Kageyu
0e981adcc6 Stop exporting std::string and std::wstring in a public header. 2015-09-11 09:14:22 +09:00
Maxime Leblanc
a18d402bd9 asftag.cpp: run astyle on added parts 2015-09-09 10:32:31 +02:00
Maxime Leblanc
dc994a65f0 ASF: full picture handling 2015-09-09 10:31:24 +02:00
Maxime Leblanc
4998dedcf4 mp4tag.cpp: run astyle on added parts 2015-09-09 10:31:08 +02:00
Maxime Leblanc
794d9fd27b MP4: full picture handling 2015-09-09 10:27:03 +02:00
Maxime Leblanc
35cf4afdba apetag.cpp: run astyle 2015-09-09 10:26:26 +02:00
Maxime Leblanc
8ecfba0c30 APE: full picture handling 2015-09-09 10:24:37 +02:00
Maxime Leblanc
ace203a6e9 id3v2tag: run astyle on added parts 2015-09-09 10:23:53 +02:00
Maxime Leblanc
ccb1d036f2 ID3v2: full picture handling 2015-09-09 10:21:15 +02:00
Maxime Leblanc
6dbc340899 Examples: adds picture handling 2015-09-09 10:20:03 +02:00
Maxime Leblanc
34931b1d3f tpicture.h,tpicturemap.h: updates comments 2015-09-09 10:18:17 +02:00
Maxime Leblanc
612c84731c tpicture: use accessors by values instead of const ref 2015-09-09 10:15:31 +02:00
Maxime Leblanc
9e95156319 tpicture: use d as for private ptr 2015-09-09 09:58:42 +02:00
Maxime Leblanc
7ed8763a33 tpicture.h,tpicturemap.h: change copyright 2015-09-09 09:58:40 +02:00
Maxime Leblanc
3ea69ed165 tpicture*: run astyle 2015-09-09 09:43:22 +02:00
Maxime Leblanc
71e8915568 Fix #94: add a unified interface for pictures 2015-09-07 14:56:49 +02:00
Tsuda Kageyu
9b8f774fb3 Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	taglib/ape/apetag.cpp
	taglib/ape/apetag.h
	taglib/mpeg/id3v2/frames/chapterframe.cpp
	taglib/riff/wav/infotag.h
2015-08-25 02:41:49 +09:00
Tsuda Kageyu
30551864fa Fix debug messages in AudioProperties classes. 2015-08-10 12:00:23 +09:00
Tsuda Kageyu
ba2167ef92 RefCounter should not be copyable. 2015-08-10 11:31:35 +09:00
Tsuda Kageyu
dc0cc4e7fa Implement 'Length in milliseconds' feature of DSF/EBML. 2015-08-10 01:35:57 +09:00
Tsuda Kageyu
ef09a707b8 Make AudioProperties::lengthInSeconds() and lengthInMilliseconds() virtual. 2015-08-10 01:10:35 +09:00
Tsuda Kageyu
400fa04b1c Remove deprecated constructors from AudioProperties classes. 2015-08-10 01:01:09 +09:00
Tsuda Kageyu
e6e11c957d Merge branch 'master' into taglib2
Conflicts:
	CMakeLists.txt
	ConfigureChecks.cmake
	config.h.cmake
	taglib/CMakeLists.txt
	taglib/ape/apefile.cpp
	taglib/ape/apefile.h
	taglib/ape/apeproperties.cpp
	taglib/ape/apeproperties.h
	taglib/ape/apetag.cpp
	taglib/asf/asfattribute.cpp
	taglib/asf/asffile.cpp
	taglib/asf/asffile.h
	taglib/asf/asfpicture.cpp
	taglib/asf/asfpicture.h
	taglib/asf/asfproperties.cpp
	taglib/asf/asfproperties.h
	taglib/audioproperties.cpp
	taglib/flac/flacfile.cpp
	taglib/flac/flacfile.h
	taglib/flac/flacproperties.cpp
	taglib/flac/flacproperties.h
	taglib/it/itproperties.cpp
	taglib/mod/modproperties.cpp
	taglib/mp4/mp4atom.cpp
	taglib/mp4/mp4file.cpp
	taglib/mp4/mp4file.h
	taglib/mp4/mp4properties.cpp
	taglib/mp4/mp4tag.cpp
	taglib/mp4/mp4tag.h
	taglib/mpc/mpcfile.cpp
	taglib/mpc/mpcfile.h
	taglib/mpc/mpcproperties.cpp
	taglib/mpc/mpcproperties.h
	taglib/mpeg/id3v2/frames/chapterframe.cpp
	taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
	taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
	taglib/mpeg/mpegfile.cpp
	taglib/mpeg/mpegfile.h
	taglib/mpeg/mpegheader.cpp
	taglib/mpeg/mpegproperties.cpp
	taglib/mpeg/mpegproperties.h
	taglib/mpeg/xingheader.cpp
	taglib/mpeg/xingheader.h
	taglib/ogg/opus/opusfile.cpp
	taglib/ogg/opus/opusfile.h
	taglib/ogg/opus/opusproperties.cpp
	taglib/ogg/opus/opusproperties.h
	taglib/ogg/speex/speexfile.cpp
	taglib/ogg/speex/speexfile.h
	taglib/ogg/speex/speexproperties.cpp
	taglib/ogg/speex/speexproperties.h
	taglib/ogg/vorbis/vorbisfile.cpp
	taglib/ogg/vorbis/vorbisfile.h
	taglib/ogg/vorbis/vorbisproperties.cpp
	taglib/ogg/vorbis/vorbisproperties.h
	taglib/riff/aiff/aifffile.cpp
	taglib/riff/aiff/aifffile.h
	taglib/riff/aiff/aiffproperties.cpp
	taglib/riff/aiff/aiffproperties.h
	taglib/riff/wav/infotag.h
	taglib/riff/wav/wavfile.cpp
	taglib/riff/wav/wavfile.h
	taglib/riff/wav/wavproperties.cpp
	taglib/riff/wav/wavproperties.h
	taglib/s3m/s3mproperties.cpp
	taglib/taglib_config.h.cmake
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tfile.cpp
	taglib/toolkit/tfile.h
	taglib/toolkit/tfilestream.cpp
	taglib/toolkit/trefcounter.cpp
	taglib/toolkit/tstring.cpp
	taglib/toolkit/tstring.h
	taglib/toolkit/tutils.h
	taglib/trueaudio/trueaudiofile.cpp
	taglib/trueaudio/trueaudiofile.h
	taglib/trueaudio/trueaudioproperties.cpp
	taglib/trueaudio/trueaudioproperties.h
	taglib/wavpack/wavpackfile.cpp
	taglib/wavpack/wavpackfile.h
	taglib/wavpack/wavpackproperties.cpp
	taglib/wavpack/wavpackproperties.h
	taglib/xm/xmproperties.cpp
	taglib/xm/xmproperties.h
	tests/CMakeLists.txt
	tests/data/alaw.wav
	tests/test_asf.cpp
	tests/test_mp4.cpp
	tests/test_ogg.cpp
	tests/test_opus.cpp
	tests/test_string.cpp
	tests/test_wav.cpp
	tests/test_wavpack.cpp
2015-08-10 00:40:22 +09:00
Lukáš Lalinský
ab2389819e Merge pull request #507 from TsudaKageyu/merge-master-to-taglib2
Merge master to taglib2
2015-05-15 19:46:52 -07:00
Tsuda Kageyu
8e35b43e32 Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	ConfigureChecks.cmake
	config.h.cmake
	taglib/CMakeLists.txt
	taglib/ape/apeproperties.cpp
	taglib/fileref.cpp
	taglib/mp4/mp4atom.cpp
	taglib/mpc/mpcproperties.cpp
	taglib/mpeg/id3v2/frames/chapterframe.cpp
	taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp
	taglib/mpeg/id3v2/id3v2frame.cpp
	taglib/mpeg/id3v2/id3v2framefactory.cpp
	taglib/mpeg/id3v2/id3v2tag.cpp
	taglib/mpeg/mpegfile.cpp
	taglib/mpeg/mpegfile.h
	taglib/riff/aiff/aifffile.cpp
	taglib/riff/aiff/aiffproperties.cpp
	taglib/riff/aiff/aiffproperties.h
	taglib/riff/wav/infotag.cpp
	taglib/riff/wav/wavfile.cpp
	taglib/riff/wav/wavproperties.cpp
	taglib/toolkit/tdebug.cpp
	taglib/toolkit/tstring.cpp
	taglib/toolkit/tutils.h
	tests/test_aiff.cpp
	tests/test_id3v2.cpp
	tests/test_wav.cpp
2015-02-18 10:07:08 +09:00
Scott Wheeler
b85a0d0710 Rebuild TRDC from v2.3 fields
This fixes an issue that was reported to me via email with the recording
date being thrown away from v2.3 tags.
2014-09-25 23:14:46 +02:00
Scott Wheeler
87040570c0 Remove deprecated (and now internally unused) createFrame declarations
This also finally marks this method as virtual, which has been a long standing
bug in TagLib 1
2014-09-25 20:48:30 +02:00
Scott Wheeler
e1b5e2c9c3 Don't leak 2014-09-25 20:45:45 +02:00
Scott Wheeler
51449f131f Missing assignment 2014-09-25 20:41:19 +02:00
Scott Wheeler
c4c4a28daa TableOfContents and ChapterFrame can be added to v2.3 or v2.4 tags 2014-09-25 19:54:57 +02:00
Scott Wheeler
d52baafa24 ByteVector::size is a size_t in taglib2 2014-09-25 19:54:57 +02:00
Scott Wheeler
bdfd7dc003 Seems to have been wrong in the merge 2014-09-25 16:44:08 +02:00
Scott Wheeler
0884945567 Merge branch 'master' into taglib2
Conflicts:
	tests/test_aiff.cpp
	tests/test_flac.cpp
2014-09-25 16:39:26 +02:00
Lukáš Lalinský
93c2758ca6 Merge pull request #432 from TsudaKageyu/lfs-check
Define only least required macros for LFS in config.h.
2014-08-22 19:26:35 +02:00
Tsuda Kageyu
2ec7a884c3 Define only least required macros for LFS in config.h. 2014-08-23 01:28:27 +09:00
Lukáš Lalinský
a5c56d31ac Merge pull request #431 from TsudaKageyu/merge-master-to-taglib2
Merge master to taglib2
2014-08-22 09:49:06 +02:00
Tsuda Kageyu
f0e8f39de1 Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	ConfigureChecks.cmake
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tstring.cpp
	taglib/xm/xmfile.cpp
	tests/test_wav.cpp
2014-08-22 13:54:02 +09:00
Lukáš Lalinský
efcd751a1c Merge pull request #412 from TsudaKageyu/largefile-ifdefs
Removed some useless #ifdefs. _LARGEFILE_SOURCE is always defined.
2014-08-04 10:16:54 +02:00
Tsuda Kageyu
34f5a7da0d Removed some useless #ifdefs. _LARGEFILE_SOURCE is always defined. 2014-08-04 14:09:08 +09:00
Lukáš Lalinský
7345b7569f Merge pull request #407 from TsudaKageyu/merge-master-to-taglib2
Merge master to taglib2
2014-07-24 10:27:18 +02:00
Tsuda Kageyu
f93397fa7b Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	ConfigureChecks.cmake
	taglib/CMakeLists.txt
	taglib/riff/aiff/aiffproperties.cpp
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tbytevector.h
	taglib/toolkit/tfilestream.cpp
	taglib/toolkit/tstring.cpp
	taglib/toolkit/tutils.h
	tests/test_apetag.cpp
	tests/test_bytevector.cpp
	tests/test_flac.cpp
	tests/test_id3v2.cpp
	tests/test_propertymap.cpp
2014-07-24 09:39:08 +09:00
Tsuda Kageyu
81f806317f Merge branch 'master' of https://github.com/taglib/taglib 2014-07-23 17:24:43 +09:00
Tsuda Kageyu
8e6e580c60 Fixed handling UTF-16 byte order. 2014-07-23 15:35:49 +09:00
Lukáš Lalinský
909d28d4fe Merge pull request #379 from TsudaKageyu/sizecheck
Robuster size checking for floating point types.
2014-07-16 17:18:43 +02:00
Lukáš Lalinský
6be3b7a1c7 Merge pull request #383 from TsudaKageyu/redundant-smartptr2
Removed some redundant code from tsmartptr.h.
2014-07-16 16:04:11 +02:00
Stephen F. Booth
29d5f75d0d Merge pull request #388 from TsudaKageyu/stringlist-export
operator<< of StringList lacks TAGLIB_EXPORT.
2014-06-16 21:25:37 -04:00
Tsuda Kageyu
8936fb2fc3 operator<< of StringList lacks TAGLIB_EXPORT. 2014-06-16 15:21:01 +09:00
Tsuda Kageyu
1dc2471d01 Removed some redundant code from tsmartptr.h. 2014-04-13 15:02:17 +09:00
Stephen F. Booth
5687c70d80 Merge pull request #382 from TsudaKageyu/no-tdebug
tdebug.h should not be included in a public header.
2014-04-11 17:38:48 -04:00
Tsuda Kageyu
3f19a522fc tdebug.h should not be included in a public header. 2014-04-12 01:28:20 +09:00
Lukáš Lalinský
3cea7f267a Merge pull request #381 from TsudaKageyu/merge-master-to-taglib2
Merged master into taglib2.
2014-04-11 13:01:57 +02:00
Tsuda Kageyu
1a9c49e42b Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	taglib/asf/asftag.cpp
	taglib/mp4/mp4tag.cpp
	taglib/toolkit/tstring.h
2014-04-11 18:31:49 +09:00
Tsuda Kageyu
76c688bffd Robuster size checking for floating point types. 2014-04-11 11:27:43 +09:00
Lukáš Lalinský
fbbebfcec6 Merge pull request #376 from TsudaKageyu/test-float80
Added a missing test for ByteVector::toFloat80().
2014-04-10 20:10:39 +02:00
Lukáš Lalinský
7f20c95cfc Merge pull request #374 from TsudaKageyu/redundant-smartptr
Removed some redundant code from tsmartptr.h.
2014-04-10 20:10:19 +02:00
Lukáš Lalinský
98c6088f91 Merge pull request #363 from TsudaKageyu/string-std-func
Simplified some functions in tstring.cpp by replacing with standard func...
2014-04-10 20:09:45 +02:00
Lukáš Lalinský
22f8b527f7 Merge pull request #373 from TsudaKageyu/snprintf-spelling
Fixed some misspellings.
2014-04-10 20:04:37 +02:00
Tsuda Kageyu
65beb8cc06 Fixed a wrong conversion in ByteVector::toFloat64BE(). 2014-04-09 14:46:42 +09:00
Tsuda Kageyu
c94d482215 Added a missing test for ByteVector::toFloat80(). 2014-04-09 14:46:42 +09:00
Tsuda Kageyu
d05101153f Fixed some misspellings. 2014-04-07 16:09:12 +09:00
Tsuda Kageyu
bceb568ea8 Removed some redundant code from tsmartptr.h. 2014-04-07 16:05:35 +09:00
Lukáš Lalinský
8390a91e48 Merge pull request #366 from TsudaKageyu/missing-ifdef
Added missing #ifdef HAVE_CONFIG_H
2014-04-04 09:37:55 +02:00
Lukáš Lalinský
4dca1ab68c Merge pull request #369 from TsudaKageyu/remove-switches
Removed some CMake switches which are no longer used.
2014-04-04 09:37:33 +02:00
Lukáš Lalinský
3ced5e92b7 Merge pull request #368 from TsudaKageyu/remove-shlwapi
Removed an unnecessary dependency on shlwapi.lib.
2014-04-04 09:37:20 +02:00
Tsuda Kageyu
dce1664f30 Removed some CMake switches which are no longer used. 2014-04-04 01:12:47 +09:00
Tsuda Kageyu
a303d88782 Removed an unnecessary dependency on shlwapi.lib. 2014-04-04 00:56:27 +09:00
Tsuda Kageyu
8b77051ecf Added missing #ifdef HAVE_CONFIG_H 2014-04-02 22:25:56 +09:00
Lukáš Lalinský
329abdbce7 Merge pull request #365 from TsudaKageyu/remove-cmake-float
Removed some unnecessary CMake checks for the size of numeric types.
2014-04-02 09:36:12 +02:00
Tsuda Kageyu
d3eefdde34 Removed some unnecessary CMake checks for the size of numeric types. 2014-04-02 14:03:35 +09:00
Tsuda Kageyu
c5353ed5ef Added UTF-8 check when constructing a String from a char. 2014-04-02 01:45:23 +09:00
Tsuda Kageyu
5199a3cbb6 Simplified some functions in tstring.cpp by replacing with standard functions. 2014-04-01 18:03:19 +09:00
Lukáš Lalinský
d93b4af8ca Merge pull request #326 from TsudaKageyu/msvc-dsf
Fixed some MSVC warnings in DSF related classes
2014-03-10 07:25:17 +01:00
Lukáš Lalinský
dd1a885f27 Merge pull request #355 from TsudaKageyu/merge-master-to-taglib2
Merge master to taglib2
2014-03-10 07:23:48 +01:00
Tsuda Kageyu
50b55a8a94 Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	taglib/ogg/opus/opusproperties.cpp
2014-03-10 11:42:05 +09:00
Lukáš Lalinský
5d519c5207 Merge pull request #350 from TsudaKageyu/merge-master-to-taglib2
Merge master to taglib2
2014-02-18 10:27:45 +01:00
Tsuda Kageyu
bd84c8928a Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	taglib/riff/wav/infotag.cpp
	taglib/toolkit/trefcounter.h
	taglib/toolkit/tstring.cpp
	taglib/toolkit/tstring.h
	taglib/xm/xmfile.cpp
	tests/test_string.cpp
2014-02-18 17:32:05 +09:00
Tsuda Kageyu
279d71c1e8 Fixed some MSVC warnings in DSF related classes 2013-12-02 23:57:24 +09:00
Stephen F. Booth
d8f5937091 Merge pull request #288 from sbooth/dsf
Added DSF support
2013-12-02 05:09:26 -08:00
Stephen F. Booth
be041ef2aa Another fix for tag stripping 2013-11-29 14:54:15 -05:00
Stephen F. Booth
d643878e9f Update internal state after saving 2013-11-29 13:38:54 -05:00
Stephen F. Booth
0c2e21024f Correctly write the metadata offset in absence of ID3v2 tag 2013-11-29 13:36:57 -05:00
Stephen F. Booth
dad73ebfc5 Strip tag if empty 2013-11-29 10:50:58 -05:00
Stephen F. Booth
37b0ba6989 Merge pull request #323 from TsudaKageyu/ifdefs
Removed some unused #ifdefs
2013-11-29 05:33:13 -08:00
Stephen F. Booth
733b537c63 Read properties more efficiently 2013-11-29 08:27:48 -05:00
Stephen F. Booth
caf705958e Validate the tag's version of file length against the actual length 2013-11-29 08:24:22 -05:00
Stephen F. Booth
ebaecc47f4 Correctly read all 8 bytes for the metadata offset 2013-11-29 08:21:23 -05:00
Stephen F. Booth
69bcc52ef3 Invalidate the file when necessary 2013-11-29 08:18:59 -05:00
Tsuda Kageyu
644b47910f Removed some unused #ifdefs 2013-11-28 14:09:16 +09:00
Stephen F. Booth
97b0f9e5a5 Merge branch 'taglib2' of github.com:taglib/taglib into dsf 2013-11-19 11:47:51 -05:00
Stephen F. Booth
3cdbdfe0b9 Merge pull request #315 from TsudaKageyu/string-redundant
Removed some redundant code from String::operator==()
2013-11-16 04:50:07 -08:00
Stephen F. Booth
7ff61ff5ac Merge pull request #317 from TsudaKageyu/comment
Amended some trivial mistakes in some comments
2013-11-16 04:46:16 -08:00
Tsuda Kageyu
f7d2935d7b Amended some trivial mistakes in some comments 2013-11-16 19:16:13 +09:00
Tsuda Kageyu
8a22c7ce75 Removed some redundant code from String::operator==() 2013-11-16 11:07:20 +09:00
Stephen F. Booth
6dc1ce7fe7 Merge pull request #314 from TsudaKageyu/backslash2
Replaced a wrongly used slash with a backslash
2013-11-15 18:03:25 -08:00
Stephen F. Booth
28cede5965 Merge pull request #313 from TsudaKageyu/merge-master-to-taglib2
Merge master to taglib2
2013-11-15 17:56:23 -08:00
Tsuda Kageyu
634d2ede3b Replaced a wrongly used slash with a backslash 2013-11-16 10:27:23 +09:00
Tsuda Kageyu
753c63e0e6 Merge branch 'master' into merge-master-to-taglib2
Conflicts:
	taglib/mp4/mp4properties.cpp
	taglib/mp4/mp4properties.h
	taglib/mpeg/id3v2/id3v2frame.cpp
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tlist.tcc
	taglib/toolkit/tmap.tcc
	taglib/toolkit/tstring.h
	taglib/wavpack/wavpackproperties.cpp
	tests/test_mp4.cpp
2013-11-16 09:38:38 +09:00
Stephen F. Booth
637a08b8b0 Merge pull request #279 from TsudaKageyu/aifc-msg
Suppressed a useless debug message in aiffproperties.cpp
2013-11-15 15:07:13 -08:00
Stephen F. Booth
0d45ddaf25 Merge pull request #312 from TsudaKageyu/string-format
Unified the string formatting functions
2013-11-15 13:19:31 -08:00
Stephen F. Booth
499d503aa2 Merge pull request #311 from TsudaKageyu/string-default-param
Fixed a wrong default parameter of String::ctor()
2013-11-15 03:55:51 -08:00
Tsuda Kageyu
116b1fcff9 Unified the string formatting functions 2013-11-15 16:34:40 +09:00
Tsuda Kageyu
85e1ef1fba Amended some comments about the Type parameters of String::ctor() 2013-11-15 15:25:18 +09:00
Tsuda Kageyu
88d55057fc Fixed a wrong default parameter of String::ctor() 2013-11-15 15:19:20 +09:00
Stephen F. Booth
cd540cbee2 Merge pull request #305 from TsudaKageyu/fix-string-upper
String::upper() no longer modifies the String itself
2013-10-30 19:45:54 -07:00
Tsuda Kageyu
0acdd2379e Added a test for String::upper() 2013-10-30 22:40:21 +09:00
Tsuda Kageyu
ced5f262ba String::upper() no longer modifies the String itself 2013-10-30 19:37:44 +09:00
Stephen F. Booth
e5c2232b10 Added tag setting test 2013-10-05 14:03:19 -04:00
Stephen F. Booth
8fc110dfd0 Added some basic tests for DSF 2013-10-05 13:59:59 -04:00
Stephen F. Booth
b949e23be3 Rename DSF::Properties to DSF::AudioProperties 2013-10-05 13:58:14 -04:00
Stephen F. Booth
43240b8ecc Fixed a comment 2013-10-05 13:51:39 -04:00
Stephen F. Booth
c09ea21ae3 Correctly handle files with no ID3v2 tag 2013-10-05 09:58:14 -04:00
Stephen F. Booth
57d12de7dd Merge pull request #281 from TsudaKageyu/tdebugh
Removed #include "tdebug.h" from a public header
2013-09-28 18:04:20 -07:00
Stephen F. Booth
0d1ed55c7e Merge pull request #278 from TsudaKageyu/riff-redundant
Removed some redundant code about checking chunk names of RIFF files
2013-09-28 17:47:53 -07:00
Stephen F. Booth
e7cfbfed76 Added DSF support 2013-09-23 21:02:30 -04:00
Tsuda Kageyu
c63dcdc459 Removed #include "tdebug.h" from a public header 2013-09-17 23:03:57 +09:00
Tsuda Kageyu
b7ffa04f20 Simplified the check for AIFF-C format 2013-09-16 21:54:12 +09:00
Tsuda Kageyu
fde99fa2fb Suppressed a useless debug message in aiffproperties.cpp 2013-09-16 04:56:33 +09:00
Tsuda Kageyu
5c9360afa2 Removed some redundant code about checking chunk names of RIFF files 2013-09-13 23:07:30 +09:00
Tsuda Kageyu
60590c0a1a Fixed a bug in appending strings and added some relevant tests 2013-09-08 14:41:35 +09:00
Lukáš Lalinský
70e58dcb21 Merge remote-tracking branch 'TsudaKageyu/taglib-config' into taglib2 2013-09-07 15:42:54 +02:00
Tsuda Kageyu
47561d8350 Unified two equivalent enums 'Endianness' and 'ByteOrder'. 2013-09-07 13:37:35 +09:00
Tsuda Kageyu
829f460c3c Merge branch 'master' into merge-master
Conflicts:
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tstring.cpp
2013-09-07 13:06:24 +09:00
Lukáš Lalinský
bb622bc163 Merge remote-tracking branch 'TsudaKageyu/forward-decl' into taglib2 2013-09-06 20:37:05 +02:00
Lukáš Lalinský
e17b8e14de Merge remote-tracking branch 'Rachus/taglib2' into taglib2 2013-09-06 20:36:29 +02:00
Sebastian Rachuj
f6c23ac92c Probable fix for http://mail.kde.org/pipermail/taglib-devel/2013-July/002516.html 2013-07-28 10:33:25 +02:00
Tsuda Kageyu
dbb4b47be3 Added a missing delete to MPEG::Header 2013-07-25 05:54:29 +09:00
Tsuda Kageyu
9f9af997ee Removed an unnecessary forward declaration 2013-07-24 15:31:27 +09:00
Tsuda Kageyu
314cc33585 Removed taglib_config.h which is no longer used 2013-07-17 18:04:02 +09:00
Tsuda Kageyu
6d40cbc04f Refactored AudioProperties classes in some ways 2013-07-13 10:38:52 +09:00
Lukáš Lalinský
6d89689c0e Fix broken merge 2013-07-11 10:23:01 +02:00
Lukáš Lalinský
48191904f1 Merge branch 'master' into taglib2
Conflicts:
	taglib/ogg/opus/opusfile.cpp
	taglib/riff/wav/wavfile.cpp
	taglib/toolkit/tstring.h
2013-07-11 10:14:09 +02:00
Tsuda Kageyu
45e8e83041 Fixed a wrong integer type 2013-06-24 21:07:33 +09:00
Lukáš Lalinský
c066ccd32d Merge branch 'master' into taglib2
Conflicts:
	taglib/toolkit/tiostream.cpp
2013-06-21 08:04:00 +02:00
Tsuda Kageyu
90d43956ec Fixed a wrong integer type 2013-06-21 11:31:51 +09:00
Tsuda Kageyu
09b574a19a Added a missing #include to fix a MSVC warning 2013-06-21 03:08:21 +09:00
Tsuda Kageyu
8be47ec8dc Fixed compilation errors in Win32 2013-06-21 01:45:53 +09:00
Lukáš Lalinský
2316a9661a Merge branch 'master' into taglib2
Conflicts:
	bindings/c/tag_c.cpp
	taglib/fileref.cpp
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tstring.cpp
2013-06-20 15:38:08 +02:00
Lukáš Lalinský
2c770600c4 Merge branch 'master' into taglib2
Conflicts:
	taglib/asf/asffile.h
	taglib/fileref.cpp
	taglib/flac/flacfile.h
	taglib/mp4/mp4file.h
	taglib/taglib_config.h.cmake
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tfile.cpp
	taglib/toolkit/tfilestream.cpp
	taglib/toolkit/tiostream.h
	tests/test_flac.cpp
2013-06-20 14:44:52 +02:00
Lukáš Lalinský
d3920f4ab6 Merge remote-tracking branch 'TsudaKageyu/vc-warnings2' into taglib2 2013-06-20 14:00:24 +02:00
Tsuda Kageyu
c9904354f9 Prevent string conversion buffer to stay in memory 2013-06-11 12:51:26 +09:00
Tsuda Kageyu
804f882e38 Uses ISO _strdup() instead of POSIX strdup() if possible 2013-06-11 12:06:29 +09:00
Tsuda Kageyu
c6f323357f Fixed some MSVC specific warnings 2013-06-10 12:49:02 +09:00
Tsuda Kageyu
25590fe70c Merge pull request #214 from TsudaKageyu/removeptr
Removed smart pointers from public headers
2013-06-01 08:05:48 -07:00
Tsuda Kageyu
5f5c670f31 Merge pull request #216 from TsudaKageyu/merge-master
Merge branch 'master' into taglib2
2013-05-23 03:13:52 -07:00
Tsuda Kageyu
8fcc992815 Merge branch 'master' into merge-master
Conflicts:
	taglib/toolkit/tfile.cpp
	taglib/toolkit/tfilestream.cpp
2013-05-23 18:36:29 +09:00
Tsuda Kageyu
7c64b1966a Removed smart pointers from public headers 2013-05-23 10:23:33 +09:00
Tsuda Kageyu
6e335694c9 Merge pull request #208 from Rachus/taglib2
A few Matroska testcases and an issue
2013-05-21 03:35:17 -07:00
Sebastian Rachuj
4be506fae2 Corrected indentation 2013-05-21 12:03:43 +02:00
Sebastian Rachuj
6bf8177796 Completed testcases and fixed some bugs, that were found because of the them 2013-05-21 11:58:03 +02:00
Tsuda Kageyu
409bba5936 Merge pull request #212 from TsudaKageyu/list
Interface change of List::find() and contains()
2013-05-20 21:01:31 -07:00
Tsuda Kageyu
ea6ab84c42 Interface change of List::find() and contains() 2013-05-21 12:45:35 +09:00
Tsuda Kageyu
d982b846c4 Merge pull request #211 from TsudaKageyu/tagunion
RIFF::WAV::Tag() returns TagUnion
2013-05-20 20:29:43 -07:00
Tsuda Kageyu
1f08a8d7c6 RIFF::WAV::Tag() returns TagUnion 2013-05-21 12:17:19 +09:00
Sebastian Rachuj
c972b0c080 Merge remote-tracking branch 'correct/taglib2' into taglib2 2013-05-21 00:27:06 +02:00
Tsuda Kageyu
a30f992106 Merge pull request #210 from TsudaKageyu/merge-master
Merge branch 'master' into taglib2
2013-05-20 14:18:57 -07:00
Tsuda Kageyu
e2a168af7a Merge branch 'master' into merge-master
Conflicts:
	taglib/toolkit/tbytevector.cpp
2013-05-21 06:08:13 +09:00
Sebastian Rachuj
8f31d882b0 Added a few testcases 2013-05-20 20:44:12 +02:00
Tsuda Kageyu
a23d41c509 Merge pull request #207 from TsudaKageyu/anonymous
Moved somethings from global to anonymous namespace.
2013-05-19 07:10:45 -07:00
Tsuda Kageyu
ca48435ab6 Moved somethings from global to anonymous namespace. 2013-05-19 23:03:15 +09:00
Tsuda Kageyu
0a4756b527 Merge pull request #206 from TsudaKageyu/smartptrfile
Rewrote File, FileRef and FileStream to use smart pointers
2013-05-19 06:17:19 -07:00
Tsuda Kageyu
437b61a311 Rewrote File, FileRef and FileStream to use smart pointers 2013-05-19 21:56:05 +09:00
Tsuda Kageyu
6c2f99c89a Merge pull request #205 from TsudaKageyu/merge-master
Merge master into TagLib2
2013-05-19 00:04:49 -07:00
Tsuda Kageyu
2b5fee2df1 Merge branch 'master' into merge-master
Conflicts:
	AUTHORS
	ConfigureChecks.cmake
	config.h.cmake
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tfilestream.cpp
	taglib/toolkit/tstring.cpp
	tests/test_id3v2.cpp
2013-05-19 15:45:15 +09:00
Tsuda Kageyu
dd7758c76e Merge pull request #200 from TsudaKageyu/smartptr
Redefined smart pointer classes in safer way
2013-05-17 22:10:00 -07:00
Tsuda Kageyu
5ed8d12478 Redefined smart pointer classes in safer way 2013-05-18 14:03:45 +09:00
Sebastian Rachuj
09e7df8509 Added return for find 2013-05-15 16:54:31 +02:00
Sebastian Rachuj
befa5724f1 Removed unnecessary casts in EBML::Element 2013-05-15 16:51:54 +02:00
Tsuda Kageyu
23418c25a4 Merge pull request #195 from TsudaKageyu/fix-float
Fixed GCC warnings about incompatible type conversions
2013-05-07 08:34:35 -07:00
Tsuda Kageyu
f07bf28f5f Fixed GCC warnings about incompatible type conversions 2013-05-08 00:27:36 +09:00
Tsuda Kageyu
2bdded5597 Merge pull request #193 from TsudaKageyu/tagunion
Changed TagUnion to take the count of tags
2013-05-06 20:17:49 -07:00
Tsuda Kageyu
8826ae2484 Changed TagUnion to take the count of tags 2013-05-07 12:01:51 +09:00
Tsuda Kageyu
2d0644dca7 Merge pull request #192 from TsudaKageyu/classname
Changed names of derived classes of AudioProperties
2013-05-06 18:40:34 -07:00
Tsuda Kageyu
4ce7ebe520 Changed names of derived classes of AudioProperties 2013-05-06 19:23:57 +09:00
Tsuda Kageyu
72bb1a887e Merge pull request #191 from TsudaKageyu/move-macros
Moved some macros from taglib_config.h to config.h.
2013-05-05 05:16:45 -07:00
Tsuda Kageyu
04e07ad4b0 Moved some macros from taglib_config.h to config.h. 2013-05-05 20:52:47 +09:00
Tsuda Kageyu
c6315d8371 Merge pull request #189 from TsudaKageyu/merge-master
Merge master
2013-05-03 09:50:22 -07:00
Tsuda Kageyu
de04f4eb19 Merge branch 'master' into merge-master
Conflicts:
	ConfigureChecks.cmake
	config.h.cmake
	taglib/CMakeLists.txt
	taglib/toolkit/taglib.h
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tmap.tcc
	taglib/toolkit/tstring.h
2013-05-04 01:38:49 +09:00
Tsuda Kageyu
73e5acdae9 Merge pull request #185 from TsudaKageyu/ieee754
IEEE754 numbers support
2013-05-01 21:49:22 -07:00
Tsuda Kageyu
7e1f3545cd IEEE754 numbers support 2013-05-02 13:41:26 +09:00
Tsuda Kageyu
8457be8ab4 Merge pull request #184 from TsudaKageyu/vc-warnings
Fixed some MSVC specific warnings
2013-05-01 06:19:01 -07:00
Tsuda Kageyu
70044534aa Fixed some MSVC specific warnings 2013-05-01 22:14:05 +09:00
Tsuda Kageyu
3e7dc496be Merge pull request #183 from TsudaKageyu/fix-win9x
Fix incompatibility with Win9x
2013-05-01 04:59:33 -07:00
Tsuda Kageyu
43cfbd568b Fix incompatibility with Win9x 2013-05-01 20:50:08 +09:00
Tsuda Kageyu
b3a3aa8a95 Merge pull request #182 from TsudaKageyu/merge-master
Merged master into taglib2
2013-05-01 04:29:40 -07:00
Tsuda Kageyu
36512745cf Merge branch 'master' into merge-master
Conflicts:
	ConfigureChecks.cmake
	config-taglib.h.cmake
	taglib/CMakeLists.txt
	taglib/ape/apefooter.cpp
	taglib/ape/apeitem.cpp
	taglib/ape/apeproperties.cpp
	taglib/asf/asfattribute.cpp
	taglib/asf/asffile.cpp
	taglib/asf/asfpicture.cpp
	taglib/fileref.cpp
	taglib/flac/flacfile.cpp
	taglib/flac/flacpicture.cpp
	taglib/flac/flacproperties.cpp
	taglib/mp4/mp4atom.cpp
	taglib/mp4/mp4coverart.cpp
	taglib/mp4/mp4item.cpp
	taglib/mp4/mp4properties.cpp
	taglib/mp4/mp4tag.cpp
	taglib/mpc/mpcproperties.cpp
	taglib/mpeg/id3v2/frames/popularimeterframe.cpp
	taglib/mpeg/id3v2/frames/relativevolumeframe.cpp
	taglib/mpeg/id3v2/id3v2frame.cpp
	taglib/mpeg/id3v2/id3v2synchdata.cpp
	taglib/mpeg/xingheader.cpp
	taglib/ogg/flac/oggflacfile.cpp
	taglib/ogg/oggpageheader.cpp
	taglib/ogg/opus/opusproperties.cpp
	taglib/ogg/speex/speexproperties.cpp
	taglib/ogg/vorbis/vorbisproperties.cpp
	taglib/ogg/xiphcomment.cpp
	taglib/riff/aiff/aiffproperties.cpp
	taglib/riff/wav/infotag.cpp
	taglib/riff/wav/wavproperties.cpp
	taglib/toolkit/taglib.h
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tbytevector.h
	taglib/toolkit/tfilestream.cpp
	taglib/toolkit/tiostream.h
	taglib/toolkit/tstring.cpp
	taglib/toolkit/tstringhandler.cpp
	taglib/trueaudio/trueaudioproperties.cpp
	taglib/wavpack/wavpackproperties.cpp
2013-05-01 20:14:31 +09:00
Tsuda Kageyu
269f34ff2a Merge pull request #172 from TsudaKageyu/tonumber4
Redesigned toNumber/fromNumber API of ByteVector
2013-05-01 02:18:24 -07:00
Tsuda Kageyu
c50a0ae1dc Merge branch 'taglib2' into tonumber4-merge
Conflicts:
	ConfigureChecks.cmake
	config-taglib.h.cmake
2013-05-01 17:44:02 +09:00
Tsuda Kageyu
6b56510f99 Merge pull request #156 from Rachus/taglib2
A Matroska implementation
2013-05-01 01:17:23 -07:00
Tsuda Kageyu
91d3b8513d Merge pull request #181 from TsudaKageyu/snprintf
Use snprintf instead of sprintf if possible.
2013-05-01 00:34:40 -07:00
Tsuda Kageyu
fbe329bb70 Use snprintf instead of sprintf if possible. 2013-05-01 14:56:59 +09:00
Tsuda Kageyu
ffc7bcfef0 Merge pull request #179 from TsudaKageyu/bytevector
Simplified copy-on-write implementation of ByteVector
2013-04-30 01:09:29 -07:00
Tsuda Kageyu
93db8aa135 Simplified copy-on-write implementation of ByteVector 2013-04-30 16:40:41 +09:00
Tsuda Kageyu
6182378c87 Merge pull request #177 from TsudaKageyu/smart-ptr
Improved reference-counted pointer
2013-04-29 05:59:59 -07:00
Tsuda Kageyu
36ceaadfaa Improved reference-counted pointer 2013-04-29 20:15:05 +09:00
Tsuda Kageyu
362900c721 Redesigned toNumber/fromNumber API of ByteVector 2013-04-27 12:46:21 +09:00
Sebastian Rachuj
fb71d7341a Correct length calculation 2013-04-19 15:24:52 +02:00
Sebastian Rachuj
3dc37a482e Changed to/from LongLong to to/from (U)Int64 2013-04-19 15:22:33 +02:00
Sebastian Rachuj
3d3c97b5ef CMakeLists adjusted for Matroska 2013-04-18 13:34:35 +02:00
Sebastian Rachuj
ea968ae3be Added a rough matroska implementation. 2013-04-18 13:34:30 +02:00
Tsuda Kageyu
82e616101a Merge pull request #152 from TsudaKageyu/missing-include
Add missing inclusions of config.h
2013-04-17 22:25:47 -07:00
Tsuda kageyu
3d8bb4d4b9 Add missing inclusions of config.h 2013-04-18 11:33:26 +09:00
Tsuda Kageyu
454abde101 Update comments in trefcountptr.h 2013-04-18 04:22:04 +09:00
Tsuda Kageyu
f97a422bc2 Merge pull request #151 from TsudaKageyu/shared_ptr
Detect C++11 features automatically
2013-04-17 11:48:06 -07:00
Tsuda kageyu
4fc2a3bdd8 Detect C++11 features automatically 2013-04-18 03:23:12 +09:00
Tsuda Kageyu
10b4bd61e2 Merge pull request #146 from TsudaKageyu/classname
Changed some class names
2013-04-16 21:23:56 -07:00
Tsuda kageyu
c3efe19d8a Changed some class names 2013-04-17 13:07:08 +09:00
Tsuda Kageyu
1390860929 Merge pull request #140 from TsudaKageyu/smart-ptr
Replace RefCounter with a smart pointer
2013-04-16 15:29:10 -07:00
Tsuda kageyu
c44351aab5 RefCounter mimics std::shared_ptr 2013-04-17 06:39:14 +09:00
Tsuda Kageyu
5c96ff42c3 Merge pull request #135 from TsudaKageyu/merge-master
Merge branch 'master' into taglib2
2013-04-15 22:39:21 -07:00
Tsuda kageyu
bb61b43ba0 Merge branch 'master' into merge-master
Conflicts:
	taglib/mp4/mp4tag.cpp
	taglib/toolkit/taglib.h
	taglib/toolkit/tbytevector.cpp
	taglib/toolkit/tbytevector.h
	taglib/toolkit/tfile.cpp
	taglib/toolkit/tstring.cpp
	taglib/toolkit/tstring.h
	taglib/trueaudio/trueaudiofile.cpp
	taglib/wavpack/wavpackfile.cpp
	taglib/wavpack/wavpackfile.h
2013-04-16 14:16:54 +09:00
Tsuda Kageyu
2f711e26ca Merge pull request #124 from TsudaKageyu/merge-bytevector
Merge ByteVector improvement made in pull request #122
2013-04-10 12:10:17 -07:00
Tsuda Kageyu
781aa05f0e Merge ByteVector improvement made in pull request #122 2013-04-11 03:52:17 +09:00
Tsuda Kageyu
c265c2a874 Merge pull request #120 from poiru/taglib2-patch-1
Change tabs in 2711555 to spaces
2013-04-03 03:42:28 -07:00
Birunthan Mohanathas
5171de33e4 Change tabs in 2711555 to spaces 2013-04-03 12:53:38 +03:00
Tsuda Kageyu
2aaf41e0bb Merge pull request #119 from TsudaKageyu/iterator
Avoid possible overruns of iterators
2013-04-02 17:40:33 -07:00
Tsuda Kageyu
27115557a0 Avoid possible iterators' out-of-range 2013-04-03 09:21:48 +09:00
Tsuda Kageyu
86cee56f74 Merge pull request #118 from TsudaKageyu/fix-compile
Fix a compilation error
2013-03-24 14:18:49 -07:00
Tsuda Kageyu
843a12a0c6 Fix a compilation error 2013-03-25 06:13:07 +09:00
Tsuda Kageyu
a0e8963fa0 Merge pull request #117 from TsudaKageyu/win32-lib
Add a required target_link_libraries in Win32
2013-03-24 13:51:21 -07:00
Tsuda Kageyu
265013ef5b Add a required target_link_libraries in Win32 2013-03-25 05:44:57 +09:00
Tsuda Kageyu
39e02ad21b Added myself to AUTHORS 2013-03-24 01:15:25 +09:00
Tsuda Kageyu
fc2b69a81e Merge pull request #114 from TsudaKageyu/size_t
Change the size type of containers from uint to size_t
2013-03-23 02:49:07 -07:00
Tsuda Kageyu
1618833a6b Fix a compilation error 2013-03-23 13:58:44 +09:00
Tsuda Kageyu
56c85a2d68 Change the size type of containers from uint to size_t 2013-03-23 13:42:46 +09:00
Tsuda Kageyu
83b6fdef72 Merge pull request #113 from TsudaKageyu/fix-ulong
Fix uses of ulong where 32-bit integers are expected
2013-03-21 19:27:31 -07:00
Tsuda Kageyu
cd082cd8e3 Fix uses of ulong where 32-bit integers are expected 2013-03-22 11:17:10 +09:00
Tsuda Kageyu
b744f66819 Merge pull request #112 from TsudaKageyu/string-data
Avoid resizing a buffer frequently in String::data()
2013-03-21 17:06:17 -07:00
Tsuda Kageyu
2ed7a59d95 Avoid resizing buffer frequently in String::data() 2013-03-22 08:58:38 +09:00
Tsuda Kageyu
7d5ce5624a Merge pull request #111 from TsudaKageyu/null
Make String:null and ByteVector::null const.
2013-03-21 10:15:23 -07:00
Tsuda Kageyu
e93696f573 Make String:null and ByteVector::null const. 2013-03-22 01:43:46 +09:00
Tsuda Kageyu
914e5f9fd8 Merge pull request #110 from TsudaKageyu/byteswap
Refector ByteVector
2013-03-21 04:09:06 -07:00
Tsuda Kageyu
b1dcdc5bd8 Refector ByteVector 2013-03-21 19:50:35 +09:00
Tsuda Kageyu
b4df82a0b0 Merge pull request #109 from TsudaKageyu/taglib2
Fix GCC warnings in FileStream
2013-03-21 02:39:17 -07:00
Tsuda Kageyu
be081d23d3 Fix GCC warnings in FileStream 2013-03-21 18:29:24 +09:00
Tsuda Kageyu
0acc22e84b Merge pull request #108 from TsudaKageyu/sizeof_wchar_t
Detect sizeof(wchar_t) at compile time
2013-03-20 22:54:28 -07:00
Tsuda Kageyu
62efb9ff17 Detect sizeof(wchar_t) at compile time 2013-03-21 14:43:03 +09:00
Tsuda Kageyu
ca5ce53b1e Merge pull request #107 from TsudaKageyu/endian-detect
Detect UTF-16 byte order at compile time
2013-03-20 18:28:27 -07:00
Tsuda Kageyu
8cae2b9f28 Detect UTF-16 byte order at compile time 2013-03-21 10:21:52 +09:00
Tsuda Kageyu
d719eb0ac6 Merge pull request #105 from TsudaKageyu/shared_ptr
Replace RefCounter with std::shared_ptr if possible
2013-03-20 18:03:57 -07:00
Tsuda Kageyu
cab68e2152 Stop determining whether to enable C++11 features at compile time 2013-03-20 08:39:13 +09:00
Tsuda Kageyu
96cf908232 Replace RefCounter with std::shared_ptr if possible 2013-03-19 21:36:08 +09:00
Tsuda Kageyu
42a74babb5 Merge pull request #103 from TsudaKageyu/string-improvement
Some improvements of String
2013-03-19 01:12:25 -07:00
Tsuda Kageyu
4e05923479 Removed null termination from return value of String::data() 2013-03-18 13:55:49 +09:00
Tsuda Kageyu
c86ea7bdff Use the standard library to convert between UTF-8 and UTF-16 where possible 2013-03-18 13:34:20 +09:00
Tsuda Kageyu
a842220fe6 Revert "Use the standard library to convert between UTF-8 and UTF-16 where possible"
This reverts commit 19ce4d0dfa.
2013-03-18 06:08:05 +09:00
Tsuda Kageyu
19ce4d0dfa Use the standard library to convert between UTF-8 and UTF-16 where possible 2013-03-18 05:56:48 +09:00
Tsuda Kageyu
6e3639de9e Avoid creating new String object when comparing 2013-03-18 02:51:11 +09:00
Tsuda Kageyu
0792eedd12 Fix UTF-16 BOM detection 2013-03-17 20:47:58 +09:00
Tsuda Kageyu
86b7cabf44 Fix UTF-16 decoding where wchar_t is not 16-bit 2013-03-17 20:27:32 +09:00
Tsuda Kageyu
de19ad72ab Fixed CPU endian detection 2013-03-17 19:40:01 +09:00
Tsuda Kageyu
9b19453059 Some improvements of String 2013-03-17 12:51:00 +09:00
Tsuda Kageyu
dbd7c151d6 Fix buffer overrun 2013-03-17 12:41:47 +09:00
Tsuda Kageyu
d3af7c0b02 Fix VC++ x64 warnings 2013-03-16 00:07:01 +09:00
Tsuda Kageyu
64447598e5 Made the destructor of StringHandler virtual. 2013-02-23 00:36:41 +09:00
Tsuda Kageyu
fba8f42588 Fix some VC spesific warnings 2013-02-22 19:29:02 +09:00
Michael Helmling
5578843220 Fixed a typo. 2013-01-03 22:54:12 +01:00
Michael Helmling
90fd336a22 Add TagUnion::removeUnsupportedProperties, further reducing SLOCs. :-) 2012-12-27 13:32:01 +01:00
Michael Helmling
fa38c805f5 Implemented TagUnion::properties() and made Tag::*properties* virtual.
This allows to remove several default implementations in types using
TagUnions.
2012-12-27 13:19:11 +01:00
Michael Helmling
b60b444d7b Merge branch 'master' into taglib2
Conflicts:
	taglib/toolkit/tfile.h
2012-12-27 11:55:12 +01:00
Lukáš Lalinský
db892c43e7 Merge branch 'master' into taglib2
Conflicts:
	taglib/mp4/mp4tag.cpp
	taglib/mp4/mp4tag.h
	taglib/toolkit/tfile.cpp
2012-11-23 10:17:16 +01:00
Lukáš Lalinský
f2b56a5511 Remove no longer needed save methods in MPEG::File 2012-11-12 16:37:06 +01:00
Lukáš Lalinský
2a86da4df5 Move Vorbis to the Ogg namespace 2012-11-12 16:32:15 +01:00
Lukáš Lalinský
f6741b65e4 Add toString() for Vorbis Comments 2012-11-12 16:27:22 +01:00
Lukáš Lalinský
60ba972244 Make the toString() method virtual 2012-11-12 16:22:23 +01:00
Lukáš Lalinský
e8ae4ecd93 Revert "Revert "Add a tool to inspect audio files, only MP4 is implemented for now""
This reverts commit c6f7ad3e83.
2012-11-12 16:16:31 +01:00
Lukáš Lalinský
f407d1456c Merge branch 'master' into taglib2 2012-11-12 16:16:18 +01:00
Lukáš Lalinský
50e616df8d Move stream operators to the TagLib namespace 2012-11-11 14:44:34 +01:00
Lukáš Lalinský
9440055eb1 Fix compilation on clang 2012-11-11 14:35:47 +01:00
Lukáš Lalinský
cb8b8d50f6 Merge branch 'master' into taglib2 2012-11-11 14:26:46 +01:00
Lukáš Lalinský
c3f9c63542 Unify ByteVectorList::split methods 2012-11-04 10:08:18 +01:00
Lukáš Lalinský
aa801e58ec Unify String::toInt methods 2012-11-04 10:04:06 +01:00
Lukáš Lalinský
9e41939eb1 Rename MPEG::XingHeader::xingHeaderOffset 2012-11-04 10:03:02 +01:00
Lukáš Lalinský
0d49e6bff0 No longer needed methods in FLAC::File 2012-11-04 10:01:39 +01:00
Lukáš Lalinský
6e2d5bc1dc Unify FLAC::File constructors 2012-11-04 09:58:56 +01:00
Lukáš Lalinský
9cede44af6 Remove deprecated constructor from FLAC::Properties 2012-11-04 09:54:17 +01:00
Lukáš Lalinský
ae11b3db38 Default parameter values in RelativeVolumeFrame 2012-11-04 09:52:03 +01:00
Lukáš Lalinský
b3c112ed99 Remove obsolete constructor from WavPack::Properties 2012-11-04 09:49:28 +01:00
Lukáš Lalinský
5b604f41be Add default value for addFramingBit to XiphComment::render() 2012-11-04 09:46:50 +01:00
Lukáš Lalinský
8599c1bd38 These functions are now virtual, so the default implementation from TagLib::File can be used 2012-11-04 09:44:51 +01:00
Lukáš Lalinský
27a078fe9b Do not need this anymore 2012-11-04 09:33:11 +01:00
Lukáš Lalinský
2b31fc2037 Merge branch 'master' into taglib2 2012-11-04 09:30:33 +01:00
Lukáš Lalinský
b01f45e141 Merge pull request #77 from TsudaKageyu/largefilesupport
Support large files over 2GB
2012-11-04 01:29:45 -07:00
Lukáš Lalinský
c46ecd186d Make the PropertyMap accessor methods virtual 2012-10-20 09:30:26 +02:00
Lukáš Lalinský
c2eecc0804 Merge branch 'master' into taglib2
Conflicts:
	taglib/mpeg/id3v1/id3v1tag.cpp
2012-10-13 13:44:38 +02:00
Tsuda Kageyu
4dcf0b41c6 Support files over 2GB 2012-10-10 22:22:29 +09:00
Tsuda Kageyu
9577784bae Add the string handler base class 2012-10-04 18:02:25 +09:00
Lukáš Lalinský
f52bab8a01 Merge branch 'master' into taglib2 2012-09-30 10:50:51 +02:00
Lukáš Lalinský
738e2ae7a7 Remove some deprecated methods from APE::Item 2012-09-30 10:42:38 +02:00
Lukáš Lalinský
231eb08396 Add a virtual destructor to FileTypeResolver 2012-09-30 10:34:14 +02:00
356 changed files with 18002 additions and 20384 deletions

View File

@@ -12,7 +12,7 @@ insert_final_newline = true
indent_style = space
indent_size = 2
# Trim trailing whitespaces
# Trim traling whitespaces
[*.{h,cpp,tcc,cmake,yml}]
trim_trailing_whitespace = true

View File

@@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -1,59 +0,0 @@
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@v4
- name: Set up Ubuntu
run: sudo apt install -y libcppunit-dev libutfcpp-dev zlib1g-dev
if: matrix.os == 'ubuntu-latest'
- name: Set up macOS
run: |
brew update
brew install cppunit utf8cpp
if: matrix.os == 'macos-latest'
- name: Set up Windows
run: vcpkg install cppunit utfcpp zlib --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 += ";$PWD\taglib\Release;$PWD\bindings\c\Release"
$env:Path += ";$env:VCPKG_INSTALLATION_ROOT\packages\cppunit_x64-windows\bin"
$env:Path += ";$env:VCPKG_INSTALLATION_ROOT\packages\utfcpp_x64-windows\bin"
$env:Path += ";$env:VCPKG_INSTALLATION_ROOT\packages\zlib_x64-windows\bin"
ctest -C ${{env.BUILD_TYPE}} -V --no-tests=error
if: matrix.os == 'windows-latest'

8
.gitignore vendored
View File

@@ -3,7 +3,6 @@ cmake_uninstall.cmake
Makefile
CTestTestfile.cmake
CMakeFiles/
CMakeLists.txt.user*
*.so
*.so.*
*.dylib
@@ -13,7 +12,6 @@ CMakeLists.txt.user*
*.suo
*.user
.*
!.github/workflows/
*~
/CMakeCache.txt
/Doxyfile
@@ -49,9 +47,3 @@ CMakeLists.txt.user*
taglib.h.stamp
taglib.xcodeproj
CMakeScripts
/.clang-format
/compile_commands.json
/build/
.clangd
.cache
.idea

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "3rdparty/utfcpp"]
path = 3rdparty/utfcpp
url = https://github.com/nemtrif/utfcpp.git

30
.travis.yml Normal file
View File

@@ -0,0 +1,30 @@
language: cpp
sudo: false
os:
- linux
- osx
dist: trusty
compiler:
- gcc
- clang
addons:
apt:
packages:
- libcppunit-dev
- zlib1g-dev
- libboost-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 -DCMAKE_CXX_FLAGS="-std=c++11" . && 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

1
3rdparty/utfcpp vendored

Submodule 3rdparty/utfcpp deleted from df857efc5b

View File

@@ -16,8 +16,6 @@ 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,14 +1,16 @@
cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR)
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
project(taglib)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
if(NOT ${CMAKE_VERSION} VERSION_LESS 2.8.12)
cmake_policy(SET CMP0022 OLD)
endif()
include(CTest)
include(FeatureSummary)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
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()
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
if(APPLE)
@@ -34,6 +36,7 @@ if(ENABLE_CCACHE)
endif()
option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF)
option(BUILD_TESTS "Build the test suite" OFF)
option(BUILD_EXAMPLES "Build the examples" OFF)
option(BUILD_BINDINGS "Build the bindings" ON)
@@ -44,26 +47,25 @@ if(PLATFORM_WINRT)
add_definitions(-DPLATFORM_WINRT)
endif()
set(TAGLIB_INSTALL_SUFFIX "" CACHE STRING
"Suffix added to installed files (include directory, libraries, .pc)")
add_definitions(-DHAVE_CONFIG_H)
set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/")
if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
endif()
## 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(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
if(MSVC)
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()
if(MSVC AND ENABLE_STATIC_RUNTIME)
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
endif()
# Read version information from file taglib/toolkit/taglib.h into variables
@@ -88,96 +90,57 @@ else()
set(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}")
endif()
# Major version: increase it if you break ABI compatibility.
# Minor version: increase it if you add ABI compatible features.
# Patch version: increase it for bug fix releases.
set(TAGLIB_SOVERSION_MAJOR 2)
set(TAGLIB_SOVERSION_MINOR 0)
set(TAGLIB_SOVERSION_PATCH 0)
# 1. If the library source code has changed at all since the last update, then increment revision.
# 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0.
# 3. If any interfaces have been added since the last public release, then increment age.
# 4. If any interfaces have been removed since the last public release, then set age to 0.
set(TAGLIB_SOVERSION_CURRENT 18)
set(TAGLIB_SOVERSION_REVISION 0)
set(TAGLIB_SOVERSION_AGE 17)
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}")
include(ConfigureChecks.cmake)
# Determine whether zlib is installed.
option(WITH_ZLIB "Build with ZLIB" ON)
if(WITH_ZLIB)
find_package("ZLIB")
set(HAVE_ZLIB ${ZLIB_FOUND})
if(ZLIB_FOUND)
set(ZLIB_LIBRARIES_FLAGS -lz)
if(NOT BUILD_SHARED_LIBS)
# When linking TagLib statically, zlib has to be linked explicitly.
set(ZLIB_INTERFACE_LINK_LIBRARIES ZLIB::ZLIB)
endif()
endif()
endif()
if(NOT WIN32)
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}"
RENAME "taglib${TAGLIB_INSTALL_SUFFIX}-config")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config" DESTINATION "${BIN_INSTALL_DIR}")
endif()
if(WIN32)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmd.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd" DESTINATION "${CMAKE_INSTALL_BINDIR}"
RENAME "taglib${TAGLIB_INSTALL_SUFFIX}-config.cmd")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd" DESTINATION "${BIN_INSTALL_DIR}")
endif()
if(NOT BUILD_FRAMEWORK)
if(IS_ABSOLUTE ${CMAKE_INSTALL_INCLUDEDIR})
set(CMAKE_PC_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
else()
set(CMAKE_PC_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
if(IS_ABSOLUTE ${CMAKE_INSTALL_LIBDIR})
set(CMAKE_PC_LIBDIR ${CMAKE_INSTALL_LIBDIR})
else()
set(CMAKE_PC_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
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 "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
RENAME "taglib${TAGLIB_INSTALL_SUFFIX}.pc")
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)
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
configure_file(config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h")
option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF)
option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF)
if(TRACE_IN_RELEASE)
set(TRACE_IN_RELEASE TRUE)
endif()
configure_file(taglib/taglib_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h")
find_package(utf8cpp QUIET)
if(NOT utf8cpp_FOUND)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/utfcpp/CMakeLists.txt)
add_subdirectory("3rdparty/utfcpp")
message(STATUS "Using utfcpp from ${utf8cpp_SOURCE_DIR}")
else()
message(FATAL_ERROR
"utfcpp not found. Either install package (probably utfcpp, utf8cpp, or libutfcpp-dev) "
"or fetch the git submodule using\n"
"git submodule update --init")
endif()
else()
message(STATUS "Using utfcpp ${utf8cpp_VERSION} from ${utf8cpp_CONFIG}")
endif()
add_subdirectory(taglib)
if(BUILD_BINDINGS)
add_subdirectory(bindings)
endif()
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()
if(BUILD_TESTS AND NOT BUILD_SHARED_LIBS)
enable_testing()
add_subdirectory(tests)
endif()
if(BUILD_EXAMPLES)
@@ -185,6 +148,7 @@ 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
@@ -193,5 +157,3 @@ 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

@@ -1,6 +1,8 @@
include(CheckLibraryExists)
include(CheckTypeSize)
include(CheckCXXCompilerFlag)
include(CheckCXXSourceCompiles)
include(TestLargeFiles)
# Check if the size of numeric types are suitable.
@@ -34,6 +36,92 @@ if(NOT ${SIZEOF_DOUBLE} EQUAL 8)
message(FATAL_ERROR "TagLib requires that double is 64-bit wide.")
endif()
# Determine whether your compiler supports large files.
if(NOT WIN32)
test_large_files(SUPPORT_LARGE_FILES)
if(NOT SUPPORT_LARGE_FILES)
MESSAGE(FATAL_ERROR "TagLib requires large files support.")
endif()
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_int x(1);
++x;
--x;
return 0;
}
" HAVE_STD_ATOMIC)
if(NOT HAVE_STD_ATOMIC)
check_cxx_source_compiles("
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_GCC_ATOMIC)
if(NOT HAVE_GCC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
int main() {
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
return 0;
}
" HAVE_MAC_ATOMIC)
if(NOT HAVE_MAC_ATOMIC)
check_cxx_source_compiles("
#include <windows.h>
int main() {
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
return 0;
}
" HAVE_WIN_ATOMIC)
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <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()
endif()
endif()
# Determine which kind of smart pointers your compiler supports.
check_cxx_source_compiles("
#include <memory>
int main() {
std::shared_ptr<int> x;
std::unique_ptr<int> y;
return 0;
}
" HAVE_STD_SMART_PTR)
# Determine which kind of byte swap functions your compiler supports.
check_cxx_source_compiles("
@@ -58,7 +146,7 @@ if(NOT HAVE_GCC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
check_cxx_source_compiles("
#include <cstdlib>
#include <stdlib.h>
int main() {
_byteswap_ushort(0);
_byteswap_ulong(0);
@@ -93,6 +181,32 @@ if(NOT HAVE_GCC_BYTESWAP)
endif()
endif()
# Determine whether your compiler supports some safer version of vsprintf.
check_cxx_source_compiles("
#include <cstdio>
#include <cstdarg>
int main() {
char buf[20];
va_list args;
vsnprintf(buf, 20, \"%d\", args);
return 0;
}
" HAVE_VSNPRINTF)
if(NOT HAVE_VSNPRINTF)
check_cxx_source_compiles("
#include <cstdio>
#include <cstdarg>
int main() {
char buf[20];
va_list args;
vsprintf_s(buf, \"%d\", args);
return 0;
}
" HAVE_VSPRINTF_S)
endif()
# Determine whether your compiler supports ISO _strdup.
check_cxx_source_compiles("
@@ -103,7 +217,28 @@ 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()
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()
# Detect WinRT mode
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
set(PLATFORM_WINRT 1)
set(PLATFORM_WINRT 1)
endif()

View File

@@ -1,79 +1,37 @@
# Doxyfile 1.9.1
# Doxyfile 1.3.4
#---------------------------------------------------------------------------
# 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
OUTPUT_TEXT_DIRECTION = None
USE_WINDOWS_ENCODING = NO
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_INC_PATH =
STRIP_FROM_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
PYTHON_DOCSTRING = YES
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
DISTRIBUTE_GROUP_DOC = 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
@@ -81,268 +39,172 @@ 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= YES
ENABLED_SECTIONS =
GENERATE_DEPRECATEDLIST= NO
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 \
*.dox
*.H
RECURSIVE = YES
EXCLUDE =
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
IMAGE_PATH =
INPUT_FILTER =
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
IGNORE_PREFIX =
COLS_IN_ALPHA_INDEX = 5
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 =
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
HTML_STYLESHEET = @CMAKE_SOURCE_DIR@/doc/taglib-api.css
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
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
DISABLE_INDEX = YES
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
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 =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
EXTRA_PACKAGES =
LATEX_HEADER =
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_SOURCE_CODE = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# 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_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
XML_SCHEMA =
XML_DTD =
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
# 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
EXPAND_AS_DEFINED =
DOXYGEN \
WITH_MP4 \
WITH_ASF
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
# Configuration::addtions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# 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
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
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
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

View File

@@ -1,4 +1,5 @@
# TagLib Installation
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.
@@ -12,429 +13,163 @@ 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
See http://www.cmake.org/cmake/help/runningcmake.html for generic help on
running CMake.
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release -DWITH_ZLIB=OFF .
make
sudo make install
Mac OS X
--------
See [cmake(1)](https://cmake.org/cmake/help/latest/manual/cmake.1.html) for
generic help on running CMake.
## Build Options
These are the most important build options. For details, have a look into the
CMakeLists.txt file.
| Option | Description |
| ----------------------- | -------------------------------------------------- |
| `BUILD_SHARED_LIBS` | Build shared libraries |
| `CMAKE_BUILD_TYPE` | Debug, Release, RelWithDebInfo, MinSizeRel |
| `BUILD_EXAMPLES` | Build examples |
| `BUILD_BINDINGS` | Build C bindings |
| `BUILD_TESTING` | Build unit tests |
| `TRACE_IN_RELEASE` | Enable debug output in release builds |
| `WITH_ZLIB` | Whether to build with ZLib (default ON) |
| `ZLIB_ROOT` | Where to find ZLib's root directory |
| `ZLIB_INCLUDE_DIR` | Where to find ZLib's include directory |
| `ZLIB_LIBRARY` | Where to find ZLib's library |
| `CMAKE_INSTALL_PREFIX` | Where to install Taglib |
| `TAGLIB_INSTALL_SUFFIX` | Suffix added to installed libraries, includes, ... |
| `ENABLE_STATIC_RUNTIME` | Link with MSVC runtime statically |
| `BUILD_FRAMEWORK` | Build a macOS framework |
If you want to install TagLib 2 alongside TagLib 1, you can use
`-DTAGLIB_INSTALL_SUFFIX=-2` and make sure that `BUILD_EXAMPLES` is not `ON`
for both versions. The installed files will then include bin/taglib-2-config,
include/taglib-2, cmake/taglib-2, pkgconfig/taglib-2.pc,
pkgconfig/taglib_c-2.pc and the libraries have a suffix "-2".
## Dependencies
A required dependency is [utf8cpp](https://github.com/nemtrif/utfcpp). You can
install the corresponding package (libutfcpp-dev on Ubuntu, utf8cpp in Homebrew,
utfcpp in vcpkg) or fetch the Git submodule with `git submodule update --init`.
Optional dependencies are
- [zlib](https://www.zlib.net/): You can disable it with `-DWITH_ZLIB=OFF`,
build and install it from the sources or use a package (zlib1g-dev on Ubuntu,
zlib in vcpkg). It is needed for compressed ID3v2 frames.
- [CppUnit](https://wiki.documentfoundation.org/Cppunit): Is required for unit
tests, which are disabled by default. If you enable them with
`-DBUILD_TESTING=ON`, you can build and install it from the sources or use a
package (libcppunit-dev on Ubuntu, cppunit in Homebrew, cppunit in vcpkg).
If the unit tests are enabled, you can run them with your build tool
(`make check`, `ninja check`) or via CMake
`cmake --build /path/to/build-dir --target check`.
## UNIX (Including Linux, BSD and macOS)
#### Building TagLib
On Linux, you can install the dependencies using the package manager of your
distribution. On macOS with Homebrew, you can use `brew install cppunit utf8cpp`
to install the dependencies.
```
# Adapt these environment variables to your directories
TAGLIB_SRC_DIR=$HOME/projects/taglib/src/taglib
TAGLIB_DST_DIR=$HOME/projects/taglib/src/build
cd $TAGLIB_SRC_DIR
cmake -B $TAGLIB_DST_DIR -DBUILD_SHARED_LIBS=ON -DVISIBILITY_HIDDEN=ON \
-DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON \
-DCMAKE_BUILD_TYPE=Release
cmake --build $TAGLIB_DST_DIR --config Release
cmake --build $TAGLIB_DST_DIR --config Release --target check
# Install to ~/pkg folder
cmake --install $TAGLIB_DST_DIR --config Release --prefix $HOME/pkg --strip
# Run example from installed package
LD_LIBRARY_PATH=$HOME/pkg/lib $HOME/pkg/bin/tagreader /path/to/audio-file
```
#### Building a Project Using TagLib
As an example for an external application using TagLib, we create a folder
taglib-client and copy the file tagreader.cpp from the examples folder
of the TagLib sources into it. We then add this simple CMakeLists.txt.
```
cmake_minimum_required(VERSION 3.5.0)
project(taglib-client)
set(CMAKE_CXX_STANDARD 17)
find_package(ZLIB)
find_package(TagLib 2.0.0 REQUIRED)
add_executable(tagreader tagreader.cpp)
target_link_libraries(tagreader TagLib::tag)
```
To build into a folder `build` inside this directory, just run
```
# Set this to the path where TagLib is installed
TAGLIB_PREFIX=$HOME/pkg
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$TAGLIB_PREFIX
cmake --build build --config Release
build/tagreader /path/to/audio-file
```
If TagLib is installed in a standard location (e.g. /usr, /usr/local), its CMake
configuration is found without setting CMAKE_INSTALL_PREFIX (or alternatives
like CMAKE_PREFIX_PATH, CMAKE_SYSTEM_PREFIX_PATH).
To use the C-bindings with tagreader_c.c, you can change the last two lines in
CMakeLists.txt to
```
add_executable(tagreader_c tagreader_c.c)
target_link_libraries(tagreader_c TagLib::tag_c)
```
#### Building a Project Using pkg-config
Before version 2.0, TagLib did not export CMake configuration, therefore
`pkg-config` could be used. This is still possible.
Note, however, that `pkg-config` makes it more difficult to use packages which
are not installed in a standard location. You can point `pkg-config` to search
in non-standard locations for .pc-files, but they still contain the install
locations defined when building TagLib. Since we did not give a
`CMAKE_INSTALL_PREFIX` in the example above, the default `/usr/local/` is used.
```
PKG_CONFIG_PATH=$HOME/pkg/lib/pkgconfig pkg-config --libs --cflags taglib
-I/usr/local/include -I/usr/local/include/taglib -L/usr/local/lib -ltag -lz
```
The following examples use the same build example with additional CMake
parameters affecting the installation location.
- Using the default prefix `-DCMAKE_INSTALL_PREFIX=/usr/local`:
```
-I/usr/local/include -I/usr/local/include/taglib -L/usr/local/lib -ltag -lz
```
- Using an absolute prefix `-DCMAKE_INSTALL_PREFIX=/usr`:
```
-I/usr/include/taglib -ltag -lz
```
- Using absolute lib and include directories
`-DCMAKE_INSTALL_LIBDIR=/abs-lib -DCMAKE_INSTALL_INCLUDEDIR=/abs-include -DCMAKE_INSTALL_PREFIX=/usr`:
```
-I/abs-include -I/abs-include/taglib -L/abs-lib -ltag -lz
```
- Using relative lib and include directories
`-DCMAKE_INSTALL_LIBDIR=rel-lib -DCMAKE_INSTALL_INCLUDEDIR=rel-include -DCMAKE_INSTALL_PREFIX=/usr`:
```
-I/usr/rel-include -I/usr/rel-include/taglib -L/usr/rel-lib -ltag -lz
```
This is the output of
```
PKG_CONFIG_PATH=$HOME/pkg/rel-lib/pkgconfig pkg-config --libs --cflags taglib
```
You could add `--define-prefix` to the `pkg-config` arguments to have the
effective location `$HOME/pkg/` instead of `/usr/` in the output.
Therefore, the correct paths for our example package would be given when using
the `--define-prefix` feature.
```
PKG_CONFIG_PATH=$HOME/pkg/lib/pkgconfig pkg-config --define-prefix --libs --cflags taglib
```
You can use pkg-config from CMake, however, relocation with `--define-prefix`
is not supported.
```
cmake_minimum_required(VERSION 3.6.0)
project(taglib-client)
find_package(PkgConfig)
pkg_check_modules(TAGLIB REQUIRED IMPORTED_TARGET taglib)
add_executable(tagreader tagreader.cpp)
target_link_libraries(tagreader PkgConfig::TAGLIB)
```
#### Framework on macOS
On macOS, you might want to build a framework that can be easily integrated
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 macOS 10.10 as the deployment target:
an Universal Binary framework with Mac OS X 10.4 as the deployment target:
mkdir build; cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF \
cmake -DCMAKE_BUILD_TYPE=Release \
-DBUILD_FRAMEWORK=ON \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.10 \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
make
-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.10 static library, use:
For a 10.6 Snow Leopard static library with both 32-bit and 64-bit code, use:
mkdir build; cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF \
cmake -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.6 \
-DCMAKE_OSX_ARCHITECTURES="i386;x86_64" \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.10 \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
make
-DCMAKE_INSTALL_PREFIX="<folder you want to build to>"
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
Windows
-------
### Using Visual Studio Build Tools
It's Windows ... Systems vary!
This means you need to adjust things to suit your system, especially paths.
For this example, we assume that you have the Visual Studio Build Tools 2022
installed. Additionally, you need [cmake](https://cmake.org/), which can be
installed for example using [scoop](https://scoop.sh/) with
`scoop install cmake`.
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
#### Building TagLib (MSVC)
Requirements:
* Tool chain, build environment, whatever ya want to call it ...
Installed and working.
* CMake program. (Available at: www.cmake.org)
Installed and working.
You can build and install the dependencies
[utf8cpp](https://github.com/nemtrif/utfcpp) and optionally
[zlib](https://www.zlib.net/) and
[CppUnit](https://wiki.documentfoundation.org/Cppunit) yourself, but it is
probably easier using a package manager such as [vcpkg](https://vcpkg.io/),
which can be installed using `scoop install vcpkg` and then install the
dependencies using `vcpkg install utfcpp zlib cppunit`.
Optional:
* Zlib library.
Available in some tool chains, not all.
Search the web, take your choice.
Now you can build TagLib from PowerShell.
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 |
---------------------| ------------|
`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) |
```
# Adapt these environment variables to your directories
$env:TAGLIB_SRC_DIR = "${env:HOMEDRIVE}${env:HOMEPATH}/projects/taglib/src/taglib"
$env:TAGLIB_DST_DIR = "${env:HOMEDRIVE}${env:HOMEPATH}/projects/taglib/src/msvs_vcpkg_build"
cd $env:TAGLIB_SRC_DIR
cmake -B $env:TAGLIB_DST_DIR -DBUILD_SHARED_LIBS=ON -DVISIBILITY_HIDDEN=ON `
-DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON `
-DCMAKE_BUILD_TYPE=Release `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" `
-G "Visual Studio 17 2022"
cmake --build $env:TAGLIB_DST_DIR --config Release
The easiest way is at the command prompt (Visual C++ command prompt for MSVS users batch file and/or shortcuts are your friends).
# Add directories containing DLL dependencies to path
$env:Path += -join(";$env:TAGLIB_DST_DIR\taglib\Release;",
"$env:TAGLIB_DST_DIR\bindings\c\Release;",
"$env:VCPKG_ROOT\packages\cppunit_x64-windows\bin;",
"$env:VCPKG_ROOT\packages\utfcpp_x64-windows\bin;",
"$env:VCPKG_ROOT\packages\zlib_x64-windows\bin")
cmake --build $env:TAGLIB_DST_DIR --config Release --target check
1. **Build the Makefiles:**
# Install to \pkg folder on current drive
cmake --install $env:TAGLIB_DST_DIR --config Release --prefix /pkg --strip
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
# Static library
$env:TAGLIB_DST_DIR = "C:/Users/fle/projects/taglib/src/msvs_vcpkg_static_build"
cmake -B $env:TAGLIB_DST_DIR -DBUILD_SHARED_LIBS=OFF -DVISIBILITY_HIDDEN=ON `
-DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON `
-DCMAKE_BUILD_TYPE=Release `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" `
-G "Visual Studio 17 2022"
cmake --build $env:TAGLIB_DST_DIR --config Release
Or use the CMake GUI:
1. Open CMake GUI.
2. Set paths: *Where is the source code* and *Where to build the binaries*.
cmake --build $env:TAGLIB_DST_DIR --config Release --target check
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
# Install to \pkg_static folder on current drive
cmake --install $env:TAGLIB_DST_DIR --config Release --prefix /pkg_static --strip
```
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.
#### Building a Project Using TagLib (MSVC)
Unit Tests
----------
As an example for an external application using TagLib, we create a folder
taglib-client and copy the file tagreader.cpp from the examples folder
of the TagLib sources into it. We then add this simple CMakeLists.txt.
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.
```
cmake_minimum_required(VERSION 3.5.0)
project(taglib-client)
set(CMAKE_CXX_STANDARD 17)
find_package(ZLIB)
find_package(TagLib 2.0.0 REQUIRED)
add_executable(tagreader tagreader.cpp)
target_link_libraries(tagreader TagLib::tag)
```
The test suite has a custom target in the build system, so you can run
the tests using make:
To build into a folder build inside this directory, just run
```
# Set this to the path where TagLib is installed
$env:TAGLIB_PREFIX = "/pkg"
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$env:TAGLIB_PREFIX" `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" `
-G "Visual Studio 17 2022"
cmake --build build --config Release
# Add directories containing DLL dependencies to path
$env:Path += ";$env:TAGLIB_PREFIX\bin;$env:VCPKG_ROOT\packages\zlib_x64-windows\bin"
build\Release\tagreader /path/to/audio-file
```
To use the C-bindings with tagreader_c.c, you can change the last two lines in
CMakeLists.txt to
```
add_executable(tagreader_c tagreader_c.c)
target_link_libraries(tagreader_c TagLib::tag_c)
```
If you link against a static TagLib, you have to adapt the installation path
(e.g. "/pkg_static") and add the following line to CMakeLists.txt
```
target_compile_definitions(tagreader_c PRIVATE TAGLIB_STATIC)
```
### Using MSYS2
#### Building TagLib (MSYS2)
To build TagLib using Clang from MSYS, install [msys2](https://www.msys2.org/),
then start the MSYS CLANG64 shell and install the dependencies as they are
specified in the [MSYS recipe for TagLib](
https://packages.msys2.org/package/mingw-w64-clang-x86_64-taglib?repo=clang64).
```
pacman -Suy
pacman -S mingw-w64-clang-x86_64-gcc-libs mingw-w64-clang-x86_64-zlib \
mingw-w64-clang-x86_64-cc mingw-w64-clang-x86_64-cmake \
mingw-w64-clang-x86_64-cppunit mingw-w64-clang-x86_64-ninja
```
Then you can build TagLib from the MSYS CLANG64 Bash.
```
# Adapt these environment variables to your directories
TAGLIB_SRC_DIR=$HOME/projects/taglib/src/taglib
TAGLIB_DST_DIR=$HOME/projects/taglib/src/msys_build
cd $TAGLIB_SRC_DIR
cmake -B $TAGLIB_DST_DIR -DBUILD_SHARED_LIBS=ON -DVISIBILITY_HIDDEN=ON \
-DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON \
-DCMAKE_BUILD_TYPE=Release -G Ninja
cmake --build $TAGLIB_DST_DIR --config Release
PATH=$PATH:/clang64/bin:$TAGLIB_DST_DIR/taglib:$TAGLIB_DST_DIR/bindings/c \
cmake --build $TAGLIB_DST_DIR --config Release --target check
# Install to /pkg_msys folder inside MSYS root (e.g. C:/msys64/pkg_msys/)
cmake --install $TAGLIB_DST_DIR --config Release --prefix /pkg_msys --strip
```
#### Building a Project Using TagLib (MSYS2)
As an example for an external application using TagLib, we create a folder
taglib-client and copy the file tagreader.cpp from the examples folder
of the TagLib sources into it. We then add this simple CMakeLists.txt.
```
cmake_minimum_required(VERSION 3.5.0)
project(taglib-client)
set(CMAKE_CXX_STANDARD 17)
find_package(ZLIB)
find_package(TagLib 2.0.0 REQUIRED)
add_executable(tagreader tagreader.cpp)
target_link_libraries(tagreader TagLib::tag)
```
To build into a folder build_msys inside this directory, just run
```
# Set this to the path where TagLib is installed
TAGLIB_PREFIX=/pkg_msys
cmake -B build_msys -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$TAGLIB_PREFIX -G Ninja
cmake --build build_msys --config Release
PATH=$PATH:$TAGLIB_PREFIX/bin
build_msys/tagreader /path/to/audio-file
```
To use the C-bindings with tagreader_c.c, you can change the last two lines in
CMakeLists.txt to
```
add_executable(tagreader_c tagreader_c.c)
target_link_libraries(tagreader_c TagLib::tag_c)
```
### Using MinGW
The instructions for MSYS2 can also be used to build with MinGW. You could use
Git Bash together with the MinGW provided by Qt.
```
# Adapt these environment variables to your directories
PATH=$PATH:/c/Qt/Tools/mingw1120_64/bin
TAGLIB_SRC_DIR=$HOME/projects/taglib/src/taglib
TAGLIB_DST_DIR=$HOME/projects/taglib/src/mingw_build
cd $TAGLIB_SRC_DIR
cmake -B $TAGLIB_DST_DIR -DBUILD_SHARED_LIBS=ON -DVISIBILITY_HIDDEN=ON \
-DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON -DWITH_ZLIB=OFF \
-DCMAKE_BUILD_TYPE=Release -G 'MinGW Makefiles'
cmake --build $TAGLIB_DST_DIR --config Release
PATH=$PATH:$TAGLIB_DST_DIR/taglib \
$TAGLIB_DST_DIR/examples/tagreader /path/to/audio-file
# Install to C:\pkg_mingw
cmake --install $TAGLIB_DST_DIR --config Release --prefix /c/pkg_mingw --strip
```
The installed package can then be used by other projects.
```
TAGLIB_PREFIX=/c/pkg_mingw
cmake -B build_mingw -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$TAGLIB_PREFIX -G 'MinGW Makefiles'
cmake --build build_mingw --config Release
PATH=$PATH:$TAGLIB_PREFIX/bin
build_mingw/tagreader /path/to/audio-file
```
make check

View File

@@ -1,194 +1,24 @@
TagLib 2.0 (Jan 24, 2024)
=========================
* New major version, binary incompatible, but source-compatible with the
latest 1.x release if no deprecated features are used.
* Requires a C++17 compiler and uses features of C++17.
* Major code cleanup, fixed warnings issued by compilers and static analyzers.
* Made methods virtual which should have been virtual but could not be
changed to keep binary compatibility, remove related workarounds.
* Removed deprecated functions:
- APE::Item::Item(const String &, const String &)
- APE::Item::toStringList(): Use values()
- APE::Item::value(): Use binaryData()
- ASF::Properties::setLength()
- ByteVector::checksum()
- ByteVector::isNull(): Use isEmpty()
- ByteVector::null
- FLAC::File::setID3v2FrameFactory()
- FLAC::File::streamInfoData()
- FLAC::File::streamLength()
- FLAC::Properties::Properties(File *, ReadStyle)
- FLAC::Properties::sampleWidth(): Use bitsPerSample()
- File::isReadable(): Use system functions
- File::isWritable(): Use system functions
- FileName::str()
- FileRef::create(): Use constructor
- MP4::Tag::itemListMap(): Use itemMap()
- MPC::File::remove(): Use strip()
- MPC::Properties::Properties(const ByteVector &, long, ReadStyle)
- MPEG::File::save(int, ...): Use overload
- MPEG::File::setID3v2FrameFactory(): Use constructor
- MPEG::ID3v2::Frame::Header::Header(const ByteVector &, bool)
- MPEG::ID3v2::Frame::Header::frameAlterPreservation(): Use
fileAlterPreservation()
- MPEG::ID3v2::Frame::Header::setData(const ByteVector &, bool)
- MPEG::ID3v2::Frame::Header::size(unsigned int): Use size()
- MPEG::ID3v2::Frame::Header::unsycronisation(): use unsynchronisation()
- MPEG::ID3v2::Frame::checkEncoding(const StringList &, String::Type): Use
checkTextEncoding(const StringList &, String::Type)
- MPEG::ID3v2::Frame::headerSize(): Use Header::size()
- MPEG::ID3v2::Frame::headerSize(unsigned int): Use
Header::size(unsigned int)
- MPEG::ID3v2::FrameFactory::createFrame(const ByteVector &, bool)
- MPEG::ID3v2::FrameFactory::createFrame(const ByteVector &, unsigned int):
Use createFrame(const ByteVector &, const Header *)
- MPEG::ID3v2::RelativeVolumeFrame::channelType()
- MPEG::ID3v2::RelativeVolumeFrame::peakVolume(): Use peakVolume(ChannelType)
- MPEG::ID3v2::RelativeVolumeFrame::setChannelType()
- MPEG::ID3v2::RelativeVolumeFrame::setPeakVolume(const PeakVolume &): Use
setPeakVolume(const PeakVolume &, ChannelType)
- MPEG::ID3v2::RelativeVolumeFrame::setVolumeAdjustment(float): Use
setVolumeAdjustment(float, ChannelType)
- MPEG::ID3v2::RelativeVolumeFrame::setVolumeAdjustmentIndex(short): Use
setVolumeAdjustmentIndex(short, ChannelType)
- MPEG::ID3v2::RelativeVolumeFrame::volumeAdjustment(): Use
volumeAdjustment(ChannelType)
- MPEG::ID3v2::RelativeVolumeFrame::volumeAdjustmentIndex(): Use
volumeAdjustmentIndex(ChannelType)
- MPEG::ID3v2::Tag::footer()
- MPEG::ID3v2::Tag::render(int): Use render(Version)
- MPEG::XingHeader::xingHeaderOffset()
- Ogg::Page::getCopyWithNewPageSequenceNumber()
- Ogg::XiphComment::removeField(): Use removeFields()
- PropertyMap::unsupportedData(): Returns now const reference, use
addUnsupportedData() to add keys
- RIFF::AIFF::Properties::Properties(const ByteVector &, ReadStyle)
- RIFF::AIFF::Properties::Properties(const ByteVector &, int, ReadStyle)
- RIFF::AIFF::Properties::sampleWidth(): Use bitsPerSample()
- RIFF::WAV::File::save(TagTypes, bool, int): Use
save(TagTypes, StripTags, Version)
- RIFF::WAV::File::tag(): Returns now a TagUnion, use ID3v2Tag() to get an
ID3v2::Tag
- String::isNull(): Use isEmpty()
- String::null
- TrueAudio::File::setID3v2FrameFactory(): Use constructor
- WavPack::Properties::Properties(const ByteVector &, long, ReadStyle)
* Behavioral changes:
- The basic tag methods (e.g. genre()) separate multiple values with " / "
instead of " ".
- The stream operator for String uses UTF-8 instead of ISO-8859-1 encoding.
- MP4 property ORIGINALDATE is mapped to "----:com.apple.iTunes:ORIGINALDATE"
instead of "----:com.apple.iTunes:originaldate".
- MP4 property ENCODEDBY is mapped to "©enc" instead of "©too", which is now
mapped to ENCODING.
* Unified interface for complex properties like pictures.
* Simplified the unified properties interface by providing its methods on
FileRef.
* C bindings: Support for properties (taglib_property_...) and complex
properties like cover art (taglib_complex_property_...), memory I/O streams.
* Support for Direct Stream Digital (DSD) stream files (DSF) and interchange
file format (DSDIFF, DFF), ADTS (AAC) files.
* The runtime version can be queried.
* Additional utility functions ByteVector::fromUShort(),
ByteVector::fromULongLong(), ByteVector::toULongLong(),
ByteVector::toULongLong(), List::sort().
* Fixed List::setAutoDelete() affecting implicitly shared copies.
* Build system: Direct support for CMake, find_package(TagLib) exports target
TagLib::tag.
* Build system: Fixed PackageConfig to support both relative and absolute paths.
* Build system: utf8cpp is no longer included, it can be provided via a system
package or a Git submodule.
* ASF: Support additional properties ARTISTWEBPAGE, ENCODING, ENCODINGTIME,
FILEWEBPAGE, INITIALKEY, ORIGINALALBUM, ORIGINALARTIST, ORIGINALFILENAME,
ORIGINALLYRICIST.
* ID3v2: Fixed extensibility of FrameFactory, use it also for WAV and AIFF
files.
* MP4: Support additional properties OWNER, RELEASEDATE.
* MP4: Introduced ItemFactory allowing clients to support new atom types.
* MP4: Detect duration from mvhd atom if not present in mdhd atom.
* MP4: Fixed type of hdvd atom to be integer instead of boolean.
* MP4: Tolerate trailing garbage in M4A files.
* MPC: Fixed content check in presence of an ID3v2 tag.
* MPEG: Do not scan full file for ID3v2 tag when ReadStyle Fast is used.
* RIFF: Support properties ALBUM, ARRANGER, ARTIST, ARTISTWEBPAGE, BPM,
COMMENT, COMPOSER, COPYRIGHT, DATE, DISCSUBTITLE, ENCODEDBY, ENCODING,
ENCODINGTIME, GENRE, ISRC, LABEL, LANGUAGE, LYRICIST, MEDIA, PERFORMER,
RELEASECOUNTRY, REMIXER, TITLE, TRACKNUMBER.
* WAV: Fixed crash with files having the "id3 " chunk as the only valid chunk.
* Windows: Fixed support for files larger than 2GB.
TagLib 1.13.1 (Jul 1, 2023)
===========================
* Fixed parsing of TXXX frames without description.
* Detect MP4 atoms with invalid length or type.
* Do not miss ID3v2 frames when an extended header is present.
* Use property "DISCSUBTITLE" for ID3v2 "TSST" frame.
* Build system improvements: Use absolute path for macOS dylib install name,
support --define-prefix when using pkg-config, fixed minimum required
CppUnit version.
* Code clean up using clang-tidy.
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 DSF and DSDIFF files.
* 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)
@@ -340,7 +170,7 @@ TagLib 1.8 (Sep 6, 2012)
* Added support for OWNE ID3 frames.
* Changed key validation in the new PropertyMap API.
* ID3v1::Tag::setStringHandler will no longer delete the previous handler,
* ID3v1::Tag::setStringHandler will no londer delete the previous handler,
the caller is responsible for this.
* File objects will also no longer delete the passed IOStream objects. It
should be done in the caller code after the File object is no longer
@@ -415,7 +245,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 successful.
conversion to a number was successfull.
* Fixed parsing of incorrectly written lengths in ID3v2 (affects mainly
compressed frames). (BUG:231075)
@@ -423,7 +253,7 @@ TagLib 1.6.2 (Apr 9, 2010)
==========================
* Read Vorbis Comments from the first FLAC metadata block, if there are
multiple ones. (BUG:211089)
multipe ones. (BUG:211089)
* Fixed a memory leak in FileRef's OGA format detection.
* Fixed compilation with the Sun Studio compiler. (BUG:215225)
* Handle WM/TrackNumber attributes with DWORD content in WMA files.
@@ -458,7 +288,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 determine if
* New cpp macros TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF to determin if
TagLib was built with MP4/ASF support.
1.6 RC1:
@@ -483,7 +313,7 @@ TagLib 1.6 (Sep 13, 2009)
and in String::operator+=. (BUG:169389)
* Added support for PRIV ID3v2 frames.
* Empty ID3v2 genres are no longer treated as numeric ID3v1 genres.
* Added support for the POPM (rating/play count) ID3v2 frame.
* Added support for the POPM (rating/playcount) ID3v2 frame.
* Generic RIFF file format support:
* Support for AIFF files with ID3v2 tags.
* Support for WAV files with ID3v2 tags.

View File

@@ -1,16 +1,16 @@
# TagLib
[![Build Status](../../actions/workflows/build.yml/badge.svg)](../../actions)
[![Build Status](https://travis-ci.org/taglib/taglib.svg?branch=master)](https://travis-ci.org/taglib/taglib)
### TagLib Audio Metadata Library
https://taglib.org/
http://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
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.
DSF, DFF, and ASF files.
TagLib is distributed under the [GNU Lesser General Public License][]
(LGPL) and [Mozilla Public License][] (MPL). Essentially that means that
@@ -18,8 +18,9 @@ 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/
[ID3v2]: http://www.id3.org
[Ogg Vorbis]: http://vorbis.com/
[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
[GNU Lesser General Public License]: http://www.gnu.org/licenses/lgpl.html
[Mozilla Public License]: http://www.mozilla.org/MPL/MPL-1.1.html

View File

@@ -1 +1 @@
add_subdirectory(c)
add_subdirectory(c)

View File

@@ -14,34 +14,20 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/wavpack
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/speex
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/trueaudio
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/riff
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/riff/aiff
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/riff/wav
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ape
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/it
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mod
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/s3m
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/xm
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/opus
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsf
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsdiff
)
set(tag_c_HDRS tag_c.h)
add_library(tag_c tag_c.cpp ${tag_c_HDRS})
target_include_directories(tag_c INTERFACE
$<INSTALL_INTERFACE:include/taglib${TAGLIB_INSTALL_SUFFIX}>
)
target_link_libraries(tag_c PRIVATE tag)
target_link_libraries(tag_c tag)
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)
set_target_properties(tag_c PROPERTIES C_VISIBILITY_PRESET hidden
)
endif()
if(BUILD_FRAMEWORK)
set_target_properties(tag_c PROPERTIES FRAMEWORK TRUE)
@@ -59,7 +45,7 @@ if(HAVE_CRUN_LIB)
# the only game in town, the three available STLs -- Cstd,
# stlport4 and stdcxx -- make this a mess. The KDE-Solaris
# team supports stdcxx (Apache RogueWave stdcxx 4.1.3).
# According to http://bugs.kde.org/show_bug.cgi?id=215225 the library can have the following two names:
find_library(ROGUEWAVE_STDCXX_LIBRARY NAMES stdcxx4 stdcxx)
if(NOT ROGUEWAVE_STDCXX_LIBRARY)
@@ -69,42 +55,21 @@ if(HAVE_CRUN_LIB)
endif()
set_target_properties(tag_c PROPERTIES
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
VERSION 0.0.0
SOVERSION 0
DEFINE_SYMBOL MAKE_TAGLIB_C_LIB
INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR}
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
)
if(TAGLIB_INSTALL_SUFFIX)
if(BUILD_SHARED_LIBS)
set(TAGLIB_LIBRARY_SUFFIX "${TAGLIB_INSTALL_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}")
else()
set(TAGLIB_LIBRARY_SUFFIX "${TAGLIB_INSTALL_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()
set_target_properties(tag_c PROPERTIES SUFFIX ${TAGLIB_LIBRARY_SUFFIX})
endif()
install(TARGETS tag_c
EXPORT taglibTargets
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/taglib${TAGLIB_INSTALL_SUFFIX}
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
)
if(NOT BUILD_FRAMEWORK)
if(IS_ABSOLUTE ${CMAKE_INSTALL_INCLUDEDIR})
set(CMAKE_PC_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
else()
set(CMAKE_PC_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
if(IS_ABSOLUTE ${CMAKE_INSTALL_LIBDIR})
set(CMAKE_PC_LIBDIR ${CMAKE_INSTALL_LIBDIR})
else()
set(CMAKE_PC_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
RENAME taglib${TAGLIB_INSTALL_SUFFIX}_c.pc)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
endif()

View File

@@ -19,45 +19,28 @@
* USA *
***************************************************************************/
#include "tag_c.h"
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <utility>
#ifdef HAVE_CONFIG_H
# include "config.h"
# include <config.h>
#endif
#include "tstringlist.h"
#include "tbytevectorlist.h"
#include "tbytevectorstream.h"
#include "tiostream.h"
#include "tfile.h"
#include "tpropertymap.h"
#include "fileref.h"
#include "asffile.h"
#include "vorbisfile.h"
#include "mpegfile.h"
#include "flacfile.h"
#include "oggflacfile.h"
#include "mpcfile.h"
#include "wavpackfile.h"
#include "speexfile.h"
#include "trueaudiofile.h"
#include "mp4file.h"
#include "aifffile.h"
#include "wavfile.h"
#include "apefile.h"
#include "itfile.h"
#include "modfile.h"
#include "s3mfile.h"
#include "xmfile.h"
#include "opusfile.h"
#include "dsffile.h"
#include "dsdifffile.h"
#include "tag.h"
#include "id3v2framefactory.h"
#include <stdlib.h>
#include <fileref.h>
#include <tfile.h>
#include <asffile.h>
#include <vorbisfile.h>
#include <mpegfile.h>
#include <flacfile.h>
#include <oggflacfile.h>
#include <mpcfile.h>
#include <wavpackfile.h>
#include <speexfile.h>
#include <trueaudiofile.h>
#include <mp4file.h>
#include <tag.h>
#include <string.h>
#include <id3v2framefactory.h>
#include "tag_c.h"
using namespace TagLib;
@@ -86,7 +69,7 @@ namespace
{
return String(s, unicodeStrings ? String::UTF8 : String::Latin1);
}
} // namespace
}
void taglib_set_strings_unicode(BOOL unicode)
{
@@ -104,22 +87,7 @@ void taglib_free(void* pointer)
}
////////////////////////////////////////////////////////////////////////////////
// TagLib::IOStream wrapper
////////////////////////////////////////////////////////////////////////////////
TagLib_IOStream *taglib_memory_iostream_new(const char *data, unsigned int size)
{
return reinterpret_cast<TagLib_IOStream *>(
new ByteVectorStream(ByteVector(data, size)));
}
void taglib_iostream_free(TagLib_IOStream *stream)
{
delete reinterpret_cast<IOStream *>(stream);
}
////////////////////////////////////////////////////////////////////////////////
// TagLib::FileRef wrapper
// TagLib::File wrapper
////////////////////////////////////////////////////////////////////////////////
TagLib_File *taglib_file_new(const char *filename)
@@ -129,78 +97,30 @@ TagLib_File *taglib_file_new(const char *filename)
TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
{
File *file = NULL;
switch(type) {
case TagLib_File_MPEG:
file = new MPEG::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new MPEG::File(filename)));
case TagLib_File_OggVorbis:
file = new Ogg::Vorbis::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::Vorbis::File(filename)));
case TagLib_File_FLAC:
file = new FLAC::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new FLAC::File(filename)));
case TagLib_File_MPC:
file = new MPC::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new MPC::File(filename)));
case TagLib_File_OggFlac:
file = new Ogg::FLAC::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::FLAC::File(filename)));
case TagLib_File_WavPack:
file = new WavPack::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new WavPack::File(filename)));
case TagLib_File_Speex:
file = new Ogg::Speex::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::Speex::File(filename)));
case TagLib_File_TrueAudio:
file = new TrueAudio::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new TrueAudio::File(filename)));
case TagLib_File_MP4:
file = new MP4::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new MP4::File(filename)));
case TagLib_File_ASF:
file = new ASF::File(filename);
break;
case TagLib_File_AIFF:
file = new RIFF::AIFF::File(filename);
break;
case TagLib_File_WAV:
file = new RIFF::WAV::File(filename);
break;
case TagLib_File_APE:
file = new APE::File(filename);
break;
case TagLib_File_IT:
file = new IT::File(filename);
break;
case TagLib_File_Mod:
file = new Mod::File(filename);
break;
case TagLib_File_S3M:
file = new S3M::File(filename);
break;
case TagLib_File_XM:
file = new XM::File(filename);
break;
case TagLib_File_Opus:
file = new Ogg::Opus::File(filename);
break;
case TagLib_File_DSF:
file = new DSF::File(filename);
break;
case TagLib_File_DSDIFF:
file = new DSDIFF::File(filename);
break;
return reinterpret_cast<TagLib_File *>(new FileRef(new ASF::File(filename)));
default:
break;
return 0;
}
return file ? reinterpret_cast<TagLib_File *>(new FileRef(file)) : NULL;
}
TagLib_File *taglib_file_new_iostream(TagLib_IOStream *stream)
{
return reinterpret_cast<TagLib_File *>(
new FileRef(reinterpret_cast<IOStream *>(stream)));
}
void taglib_file_free(TagLib_File *file)
@@ -210,18 +130,18 @@ void taglib_file_free(TagLib_File *file)
BOOL taglib_file_is_valid(const TagLib_File *file)
{
return !reinterpret_cast<const FileRef *>(file)->isNull();
return reinterpret_cast<const FileRef *>(file)->isValid();
}
TagLib_Tag *taglib_file_tag(const TagLib_File *file)
{
auto f = reinterpret_cast<const FileRef *>(file);
const FileRef *f = reinterpret_cast<const FileRef *>(file);
return reinterpret_cast<TagLib_Tag *>(f->tag());
}
const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file)
{
auto f = reinterpret_cast<const FileRef *>(file);
const FileRef *f = reinterpret_cast<const FileRef *>(file);
return reinterpret_cast<const TagLib_AudioProperties *>(f->audioProperties());
}
@@ -338,8 +258,8 @@ void taglib_tag_free_strings()
if(!stringManagementEnabled)
return;
for(auto &string : std::as_const(strings))
free(string);
for(List<char *>::ConstIterator it = strings.begin(); it != strings.end(); ++it)
free(*it);
strings.clear();
}
@@ -349,25 +269,25 @@ void taglib_tag_free_strings()
int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties)
{
auto p = reinterpret_cast<const AudioProperties *>(audioProperties);
return p->lengthInSeconds();
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
return p->length();
}
int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties)
{
auto p = reinterpret_cast<const AudioProperties *>(audioProperties);
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
return p->bitrate();
}
int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties)
{
auto p = reinterpret_cast<const AudioProperties *>(audioProperties);
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
return p->sampleRate();
}
int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties)
{
auto p = reinterpret_cast<const AudioProperties *>(audioProperties);
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
return p->channels();
}
@@ -393,423 +313,3 @@ void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding)
ID3v2::FrameFactory::instance()->setDefaultTextEncoding(type);
}
/******************************************************************************
* Properties API
******************************************************************************/
namespace {
void _taglib_property_set(TagLib_File *file, const char* prop, const char* value, bool append)
{
if(file == NULL || prop == NULL)
return;
auto tfile = reinterpret_cast<FileRef *>(file);
PropertyMap map = tfile->tag()->properties();
if(value) {
auto property = map.find(prop);
if(property == map.end()) {
map.insert(prop, StringList(value));
}
else {
if(append) {
property->second.append(value);
}
else {
property->second = StringList(value);
}
}
}
else {
map.erase(prop);
}
tfile->setProperties(map);
}
} // namespace
void taglib_property_set(TagLib_File *f, const char *prop, const char *value)
{
_taglib_property_set(f, prop, value, false);
}
void taglib_property_set_append(TagLib_File *f, const char *prop, const char *value)
{
_taglib_property_set(f, prop, value, true);
}
char** taglib_property_keys(TagLib_File *file)
{
if(file == NULL)
return NULL;
const PropertyMap map = reinterpret_cast<const FileRef *>(file)->properties();
if(map.isEmpty())
return NULL;
auto props = static_cast<char **>(malloc(sizeof(char *) * (map.size() + 1)));
char **pp = props;
for(const auto &i : map) {
*pp++ = stringToCharArray(i.first);
}
*pp = NULL;
return props;
}
char **taglib_property_get(TagLib_File *file, const char *prop)
{
if(file == NULL || prop == NULL)
return NULL;
const PropertyMap map = reinterpret_cast<const FileRef *>(file)->properties();
auto property = map.find(prop);
if(property == map.end())
return NULL;
auto props = static_cast<char **>(malloc(sizeof(char *) * (property->second.size() + 1)));
char **pp = props;
for(const auto &i : property->second) {
*pp++ = stringToCharArray(i);
}
*pp = NULL;
return props;
}
void taglib_property_free(char **props)
{
if(props == NULL)
return;
char **p = props;
while(*p) {
free(*p++);
}
free(props);
}
/******************************************************************************
* Complex Properties API
******************************************************************************/
namespace {
bool _taglib_complex_property_set(
TagLib_File *file, const char *key,
const TagLib_Complex_Property_Attribute **value, bool append)
{
if(file == NULL || key == NULL)
return false;
auto tfile = reinterpret_cast<FileRef *>(file);
if(value == NULL) {
return tfile->setComplexProperties(key, {});
}
VariantMap map;
const TagLib_Complex_Property_Attribute** attrPtr = value;
while(*attrPtr) {
const TagLib_Complex_Property_Attribute *attr = *attrPtr;
String attrKey(attr->key);
TagLib_Variant_Type type = attr->value.type;
switch(type) {
case TagLib_Variant_Void:
map.insert(attrKey, Variant());
break;
case TagLib_Variant_Bool:
map.insert(attrKey, attr->value.value.boolValue != 0);
break;
case TagLib_Variant_Int:
map.insert(attrKey, attr->value.value.intValue);
break;
case TagLib_Variant_UInt:
map.insert(attrKey, attr->value.value.uIntValue);
break;
case TagLib_Variant_LongLong:
map.insert(attrKey, attr->value.value.longLongValue);
break;
case TagLib_Variant_ULongLong:
map.insert(attrKey, attr->value.value.uLongLongValue);
break;
case TagLib_Variant_Double:
map.insert(attrKey, attr->value.value.doubleValue);
break;
case TagLib_Variant_String:
map.insert(attrKey, attr->value.value.stringValue);
break;
case TagLib_Variant_StringList: {
StringList strs;
if(attr->value.value.stringListValue) {
char **s = attr->value.value.stringListValue;;
while(*s) {
strs.append(*s++);
}
}
map.insert(attrKey, strs);
break;
}
case TagLib_Variant_ByteVector:
map.insert(attrKey, ByteVector(attr->value.value.byteVectorValue,
attr->value.size));
break;
}
++attrPtr;
}
return append ? tfile->setComplexProperties(key, tfile->complexProperties(key).append(map))
: tfile->setComplexProperties(key, {map});
}
} // namespace
BOOL taglib_complex_property_set(
TagLib_File *file, const char *key,
const TagLib_Complex_Property_Attribute **value)
{
return _taglib_complex_property_set(file, key, value, false);
}
BOOL taglib_complex_property_set_append(
TagLib_File *file, const char *key,
const TagLib_Complex_Property_Attribute **value)
{
return _taglib_complex_property_set(file, key, value, true);
}
char** taglib_complex_property_keys(TagLib_File *file)
{
if(file == NULL) {
return NULL;
}
const StringList strs = reinterpret_cast<const FileRef *>(file)->complexPropertyKeys();
if(strs.isEmpty()) {
return NULL;
}
auto keys = static_cast<char **>(malloc(sizeof(char *) * (strs.size() + 1)));
char **keyPtr = keys;
for(const auto &str : strs) {
*keyPtr++ = stringToCharArray(str);
}
*keyPtr = NULL;
return keys;
}
TagLib_Complex_Property_Attribute*** taglib_complex_property_get(
TagLib_File *file, const char *key)
{
if(file == NULL || key == NULL) {
return NULL;
}
const auto variantMaps = reinterpret_cast<const FileRef *>(file)->complexProperties(key);
if(variantMaps.isEmpty()) {
return NULL;
}
TagLib_Complex_Property_Attribute ***props = static_cast<TagLib_Complex_Property_Attribute ***>(
malloc(sizeof(TagLib_Complex_Property_Attribute **) * (variantMaps.size() + 1)));
TagLib_Complex_Property_Attribute ***propPtr = props;
for(const auto &variantMap : variantMaps) {
if(!variantMap.isEmpty()) {
TagLib_Complex_Property_Attribute **attrs = static_cast<TagLib_Complex_Property_Attribute **>(
malloc(sizeof(TagLib_Complex_Property_Attribute *) * (variantMap.size() + 1)));
TagLib_Complex_Property_Attribute *attr = static_cast<TagLib_Complex_Property_Attribute *>(
malloc(sizeof(TagLib_Complex_Property_Attribute) * variantMap.size()));
TagLib_Complex_Property_Attribute **attrPtr = attrs;
// The next assignment is redundant to silence the clang analyzer,
// it is done at the end of the loop, which must be entered because
// variantMap is not empty.
*attrPtr = attr;
for(const auto &[k, v] : variantMap) {
attr->key = stringToCharArray(k);
attr->value.size = 0;
switch(v.type()) {
case Variant::Void:
attr->value.type = TagLib_Variant_Void;
attr->value.value.stringValue = NULL;
break;
case Variant::Bool:
attr->value.type = TagLib_Variant_Bool;
attr->value.value.boolValue = v.value<bool>();
break;
case Variant::Int:
attr->value.type = TagLib_Variant_Int;
attr->value.value.intValue = v.value<int>();
break;
case Variant::UInt:
attr->value.type = TagLib_Variant_UInt;
attr->value.value.uIntValue = v.value<unsigned int>();
break;
case Variant::LongLong:
attr->value.type = TagLib_Variant_LongLong;
attr->value.value.longLongValue = v.value<long long>();
break;
case Variant::ULongLong:
attr->value.type = TagLib_Variant_ULongLong;
attr->value.value.uLongLongValue = v.value<unsigned long long>();
break;
case Variant::Double:
attr->value.type = TagLib_Variant_Double;
attr->value.value.doubleValue = v.value<double>();
break;
case Variant::String: {
attr->value.type = TagLib_Variant_String;
auto str = v.value<String>();
attr->value.value.stringValue = stringToCharArray(str);
attr->value.size = str.size();
break;
}
case Variant::StringList: {
attr->value.type = TagLib_Variant_StringList;
StringList strs = v.value<StringList>();
auto strPtr = static_cast<char **>(malloc(sizeof(char *) * (strs.size() + 1)));
attr->value.value.stringListValue = strPtr;
attr->value.size = strs.size();
for(const auto &str : strs) {
*strPtr++ = stringToCharArray(str);
}
*strPtr = NULL;
break;
}
case Variant::ByteVector: {
attr->value.type = TagLib_Variant_ByteVector;
const ByteVector data = v.value<ByteVector>();
auto bytePtr = static_cast<char *>(malloc(data.size()));
attr->value.value.byteVectorValue = bytePtr;
attr->value.size = data.size();
::memcpy(bytePtr, data.data(), data.size());
break;
}
case Variant::ByteVectorList:
case Variant::VariantList:
case Variant::VariantMap: {
attr->value.type = TagLib_Variant_String;
std::stringstream ss;
ss << v;
attr->value.value.stringValue = stringToCharArray(ss.str());
break;
}
}
*attrPtr++ = attr++;
}
*attrPtr = NULL;
*propPtr++ = attrs;
}
}
*propPtr = NULL;
return props;
}
void taglib_picture_from_complex_property(
TagLib_Complex_Property_Attribute*** properties,
TagLib_Complex_Property_Picture_Data *picture)
{
if(!properties || !picture) {
return;
}
std::memset(picture, 0, sizeof(*picture));
TagLib_Complex_Property_Attribute*** propPtr = properties;
while(!picture->data && *propPtr) {
TagLib_Complex_Property_Attribute** attrPtr = *propPtr;
while(*attrPtr) {
TagLib_Complex_Property_Attribute *attr = *attrPtr;
TagLib_Variant_Type type = attr->value.type;
switch(type) {
case TagLib_Variant_String:
if(strcmp("mimeType", attr->key) == 0) {
picture->mimeType = attr->value.value.stringValue;
}
else if(strcmp("description", attr->key) == 0) {
picture->description = attr->value.value.stringValue;
}
else if(strcmp("pictureType", attr->key) == 0) {
picture->pictureType = attr->value.value.stringValue;
}
break;
case TagLib_Variant_ByteVector:
if(strcmp("data", attr->key) == 0) {
picture->data = attr->value.value.byteVectorValue;
picture->size = attr->value.size;
}
break;
default:
break;
}
++attrPtr;
}
++propPtr;
}
}
void taglib_complex_property_free_keys(char **keys)
{
if(keys == NULL) {
return;
}
char **k = keys;
while(*k) {
free(*k++);
}
free(keys);
}
void taglib_complex_property_free(
TagLib_Complex_Property_Attribute ***props)
{
if(props == NULL) {
return;
}
TagLib_Complex_Property_Attribute*** propPtr = props;
while(*propPtr) {
TagLib_Complex_Property_Attribute** attrPtr = *propPtr;
while(*attrPtr) {
TagLib_Complex_Property_Attribute *attr = *attrPtr;
TagLib_Variant_Type type = attr->value.type;
switch(type) {
case TagLib_Variant_String:
free(attr->value.value.stringValue);
break;
case TagLib_Variant_StringList:
if(attr->value.value.stringListValue) {
char **s = attr->value.value.stringListValue;
while(*s) {
free(*s++);
}
free(attr->value.value.stringListValue);
}
break;
case TagLib_Variant_ByteVector:
free(attr->value.value.byteVectorValue);
break;
case TagLib_Variant_Void:
case TagLib_Variant_Bool:
case TagLib_Variant_Int:
case TagLib_Variant_UInt:
case TagLib_Variant_LongLong:
case TagLib_Variant_ULongLong:
case TagLib_Variant_Double:
break;
}
free(attr->key);
++attrPtr;
}
free(**propPtr);
free(*propPtr++);
}
free(props);
}

View File

@@ -43,10 +43,7 @@ extern "C" {
#define TAGLIB_C_EXPORT
#endif
#ifdef _MSC_VER
/* minwindef.h contains typedef int BOOL */
#include <windows.h>
#elif !defined BOOL
#ifndef BOOL
#define BOOL int
#endif
@@ -60,15 +57,14 @@ extern "C" {
*******************************************************************************/
/*
* These are used to give the C API some type safety (as opposed to
* using void * ), but pointers to them are simply cast to the corresponding C++
* These are used for type provide some type safety to the C API (as opposed to
* using void *, but pointers to them are simply cast to the corresponding C++
* types in the implementation.
*/
typedef struct { int dummy; } TagLib_File;
typedef struct { int dummy; } TagLib_Tag;
typedef struct { int dummy; } TagLib_AudioProperties;
typedef struct { int dummy; } TagLib_IOStream;
/*!
* By default all strings coming into or out of TagLib's C API are in UTF8.
@@ -90,22 +86,6 @@ TAGLIB_C_EXPORT void taglib_set_string_management_enabled(BOOL management);
*/
TAGLIB_C_EXPORT void taglib_free(void* pointer);
/*******************************************************************************
* Stream API
******************************************************************************/
/*!
* Creates a byte vector stream from \a size bytes of \a data.
* Such a stream can be used with taglib_file_new_iostream() to create a file
* from memory.
*/
TAGLIB_C_EXPORT TagLib_IOStream *taglib_memory_iostream_new(const char *data, unsigned int size);
/*!
* Frees and closes the stream.
*/
TAGLIB_C_EXPORT void taglib_iostream_free(TagLib_IOStream *stream);
/*******************************************************************************
* File API
******************************************************************************/
@@ -120,17 +100,7 @@ typedef enum {
TagLib_File_Speex,
TagLib_File_TrueAudio,
TagLib_File_MP4,
TagLib_File_ASF,
TagLib_File_AIFF,
TagLib_File_WAV,
TagLib_File_APE,
TagLib_File_IT,
TagLib_File_Mod,
TagLib_File_S3M,
TagLib_File_XM,
TagLib_File_Opus,
TagLib_File_DSF,
TagLib_File_DSDIFF
TagLib_File_ASF
} TagLib_File_Type;
/*!
@@ -148,16 +118,6 @@ TAGLIB_C_EXPORT TagLib_File *taglib_file_new(const char *filename);
*/
TAGLIB_C_EXPORT TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type);
/*!
* Creates a TagLib file from a \a stream.
* A byte vector stream can be used to read a file from memory and write to
* memory, e.g. when fetching network data.
* The stream has to be created using taglib_memory_iostream_new() and shall be
* freed using taglib_iostream_free() \e after this file is freed with
* taglib_file_free().
*/
TAGLIB_C_EXPORT TagLib_File *taglib_file_new_iostream(TagLib_IOStream *stream);
/*!
* Frees and closes the file.
*/
@@ -332,275 +292,6 @@ typedef enum {
TAGLIB_C_EXPORT void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding);
/******************************************************************************
* Properties API
******************************************************************************/
/*!
* Sets the property \a prop with \a value. Use \a value = NULL to remove
* the property, otherwise it will be replaced.
*/
TAGLIB_C_EXPORT void taglib_property_set(TagLib_File *file, const char *prop, const char *value);
/*!
* Appends \a value to the property \a prop (sets it if non-existing).
* Use \a value = NULL to remove all values associated with the property.
*/
TAGLIB_C_EXPORT void taglib_property_set_append(TagLib_File *file, const char *prop, const char *value);
/*!
* Get the keys of the property map.
*
* \return NULL terminated array of C-strings (char *), only NULL if empty.
* It must be freed by the client using taglib_property_free().
*/
TAGLIB_C_EXPORT char** taglib_property_keys(TagLib_File *file);
/*!
* Get value(s) of property \a prop.
*
* \return NULL terminated array of C-strings (char *), only NULL if empty.
* It must be freed by the client using taglib_property_free().
*/
TAGLIB_C_EXPORT char** taglib_property_get(TagLib_File *file, const char *prop);
/*!
* Frees the NULL terminated array \a props and the C-strings it contains.
*/
TAGLIB_C_EXPORT void taglib_property_free(char **props);
/******************************************************************************
* Complex Properties API
******************************************************************************/
/*!
* Types which can be stored in a TagLib_Variant.
*
* \related TagLib::Variant::Type
* These correspond to TagLib::Variant::Type, but ByteVectorList, VariantList,
* VariantMap are not supported and will be returned as their string
* representation.
*/
typedef enum {
TagLib_Variant_Void,
TagLib_Variant_Bool,
TagLib_Variant_Int,
TagLib_Variant_UInt,
TagLib_Variant_LongLong,
TagLib_Variant_ULongLong,
TagLib_Variant_Double,
TagLib_Variant_String,
TagLib_Variant_StringList,
TagLib_Variant_ByteVector
} TagLib_Variant_Type;
/*!
* Discriminated union used in complex property attributes.
*
* \e type must be set according to the \e value union used.
* \e size is only required for TagLib_Variant_ByteVector and must contain
* the number of bytes.
*
* \related TagLib::Variant.
*/
typedef struct {
TagLib_Variant_Type type;
unsigned int size;
union {
char *stringValue;
char *byteVectorValue;
char **stringListValue;
BOOL boolValue;
int intValue;
unsigned int uIntValue;
long long longLongValue;
unsigned long long uLongLongValue;
double doubleValue;
} value;
} TagLib_Variant;
/*!
* Attribute of a complex property.
* Complex properties consist of a NULL-terminated array of pointers to
* this structure with \e key and \e value.
*/
typedef struct {
char *key;
TagLib_Variant value;
} TagLib_Complex_Property_Attribute;
/*!
* Picture data extracted from a complex property by the convenience function
* taglib_picture_from_complex_property().
*/
typedef struct {
char *mimeType;
char *description;
char *pictureType;
char *data;
unsigned int size;
} TagLib_Complex_Property_Picture_Data;
/*!
* Declare complex property attributes to set a picture.
* Can be used to define a variable \a var which can be used with
* taglib_complex_property_set() and a "PICTURE" key to set an
* embedded picture with the picture data \a dat of size \a siz
* and description \a desc, mime type \a mime and picture type
* \a typ (size is unsigned int, the other input parameters char *).
*/
#define TAGLIB_COMPLEX_PROPERTY_PICTURE(var, dat, siz, desc, mime, typ) \
const TagLib_Complex_Property_Attribute \
var##Attrs[] = { \
{ \
(char *)"data", \
{ \
TagLib_Variant_ByteVector, \
(siz), \
{ \
(char *)(dat) \
} \
} \
}, \
{ \
(char *)"mimeType", \
{ \
TagLib_Variant_String, \
0U, \
{ \
(char *)(mime) \
} \
} \
}, \
{ \
(char *)"description", \
{ \
TagLib_Variant_String, \
0U, \
{ \
(char *)(desc) \
} \
} \
}, \
{ \
(char *)"pictureType", \
{ \
TagLib_Variant_String, \
0U, \
{ \
(char *)(typ) \
} \
} \
} \
}; \
const TagLib_Complex_Property_Attribute *var[] = { \
&var##Attrs[0], &var##Attrs[1], &var##Attrs[2], \
&var##Attrs[3], NULL \
}
/*!
* Sets the complex property \a key with \a value. Use \a value = NULL to
* remove the property, otherwise it will be replaced with the NULL
* terminated array of attributes in \a value.
*
* A picture can be set with the TAGLIB_COMPLEX_PROPERTY_PICTURE macro:
*
* \code {.c}
* TagLib_File *file = taglib_file_new("myfile.mp3");
* FILE *fh = fopen("mypicture.jpg", "rb");
* if(fh) {
* fseek(fh, 0L, SEEK_END);
* long size = ftell(fh);
* fseek(fh, 0L, SEEK_SET);
* char *data = (char *)malloc(size);
* fread(data, size, 1, fh);
* TAGLIB_COMPLEX_PROPERTY_PICTURE(props, data, size, "Written by TagLib",
* "image/jpeg", "Front Cover");
* taglib_complex_property_set(file, "PICTURE", props);
* taglib_file_save(file);
* free(data);
* fclose(fh);
* }
* \endcode
*/
TAGLIB_C_EXPORT BOOL taglib_complex_property_set(
TagLib_File *file, const char *key,
const TagLib_Complex_Property_Attribute **value);
/*!
* Appends \a value to the complex property \a key (sets it if non-existing).
* Use \a value = NULL to remove all values associated with the \a key.
*/
TAGLIB_C_EXPORT BOOL taglib_complex_property_set_append(
TagLib_File *file, const char *key,
const TagLib_Complex_Property_Attribute **value);
/*!
* Get the keys of the complex properties.
*
* \return NULL terminated array of C-strings (char *), only NULL if empty.
* It must be freed by the client using taglib_complex_property_free_keys().
*/
TAGLIB_C_EXPORT char** taglib_complex_property_keys(TagLib_File *file);
/*!
* Get value(s) of complex property \a key.
*
* \return NULL terminated array of property values, which are themselves an
* array of property attributes, only NULL if empty.
* It must be freed by the client using taglib_complex_property_free().
*/
TAGLIB_C_EXPORT TagLib_Complex_Property_Attribute*** taglib_complex_property_get(
TagLib_File *file, const char *key);
/*!
* Extract the complex property values of a picture.
*
* This function can be used to get the data from a "PICTURE" complex property
* without having to traverse the whole variant map. A picture can be
* retrieved like this:
*
* \code {.c}
* TagLib_File *file = taglib_file_new("myfile.mp3");
* TagLib_Complex_Property_Attribute*** properties =
* taglib_complex_property_get(file, "PICTURE");
* TagLib_Complex_Property_Picture_Data picture;
* taglib_picture_from_complex_property(properties, &picture);
* // Do something with picture.mimeType, picture.description,
* // picture.pictureType, picture.data, picture.size, e.g. extract it.
* FILE *fh = fopen("mypicture.jpg", "wb");
* if(fh) {
* fwrite(picture.data, picture.size, 1, fh);
* fclose(fh);
* }
* taglib_complex_property_free(properties);
* \endcode
*
* Note that the data in \a picture contains pointers to data in \a properties,
* i.e. it only lives as long as the properties, until they are freed with
* taglib_complex_property_free().
* If you want to access multiple pictures or additional properties of FLAC
* pictures ("width", "height", "numColors", "colorDepth" int values), you
* have to traverse the \a properties yourself.
*/
TAGLIB_C_EXPORT void taglib_picture_from_complex_property(
TagLib_Complex_Property_Attribute*** properties,
TagLib_Complex_Property_Picture_Data *picture);
/*!
* Frees the NULL terminated array \a keys (as returned by
* taglib_complex_property_keys()) and the C-strings it contains.
*/
TAGLIB_C_EXPORT void taglib_complex_property_free_keys(char **keys);
/*!
* Frees the NULL terminated array \a props of property attribute arrays
* (as returned by taglib_complex_property_get()) and the data such as
* C-strings and byte vectors contained in these attributes.
*/
TAGLIB_C_EXPORT void taglib_complex_property_free(
TagLib_Complex_Property_Attribute ***props);
#ifdef __cplusplus
}
#endif

View File

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

View File

@@ -0,0 +1,9 @@
#include <sys/types.h>
int main(int argc, char **argv)
{
/* Cause a compile-time error if off_t is smaller than 64 bits */
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[ (LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1 ];
return 0;
}

View File

@@ -0,0 +1,23 @@
#cmakedefine _LARGEFILE_SOURCE
#cmakedefine _LARGEFILE64_SOURCE
#cmakedefine _LARGE_FILES
#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
/* Cause a compile-time error if off_t is smaller than 64 bits,
* and make sure we have ftello / fseeko.
*/
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[ (LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1 ];
FILE *fp = fopen(argv[0],"r");
off_t offset = ftello( fp );
fseeko( fp, offset, SEEK_CUR );
fclose(fp);
return 0;
}

View File

@@ -8,7 +8,7 @@
include (MacroEnsureVersion)
if(NOT CPPUNIT_MIN_VERSION)
SET(CPPUNIT_MIN_VERSION 1.14.0)
SET(CPPUNIT_MIN_VERSION 1.12.0)
endif(NOT CPPUNIT_MIN_VERSION)
FIND_PROGRAM(CPPUNIT_CONFIG_EXECUTABLE cppunit-config )
@@ -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 your cppunit installed version is at least ${CPPUNIT_MIN_VERSION}")
MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}")
SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION})
ENDIF(CPPUNIT_CONFIG_EXECUTABLE)
@@ -56,7 +56,7 @@ IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
macro_ensure_version( ${CPPUNIT_MIN_VERSION} ${CPPUNIT_INSTALLED_VERSION} CPPUNIT_INSTALLED_VERSION_OK )
IF(NOT CPPUNIT_INSTALLED_VERSION_OK)
MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or newer is required")
MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or major is required")
SET(CppUnit_FOUND FALSE)
ENDIF(NOT CPPUNIT_INSTALLED_VERSION_OK)

View File

@@ -0,0 +1,104 @@
# - Define macro to check large file support
#
# TEST_LARGE_FILES(VARIABLE)
#
# VARIABLE will be set to true if off_t is 64 bits, and fseeko/ftello present.
# This macro will also set defines necessary enable large file support, for instance
# _LARGE_FILES
# _LARGEFILE_SOURCE
# _FILE_OFFSET_BITS 64
# HAVE_FSEEKO
#
# However, it is YOUR job to make sure these defines are set in a cmakedefine so they
# end up in a config.h file that is included in your source if necessary!
# This macro skips the Windows specific checks. Because TagLib uses Win32 API.
MACRO(TEST_LARGE_FILES VARIABLE)
IF(NOT DEFINED ${VARIABLE})
# On most platforms it is probably overkill to first test the flags for 64-bit off_t,
# and then separately fseeko. However, in the future we might have 128-bit filesystems
# (ZFS), so it might be dangerous to indiscriminately set e.g. _FILE_OFFSET_BITS=64.
MESSAGE(STATUS "Checking for 64-bit off_t")
# First check without any special flags
TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}"
"${CMAKE_SOURCE_DIR}/cmake/TestFileOffsetBits.c")
if(FILE64_OK)
MESSAGE(STATUS "Checking for 64-bit off_t - present")
endif(FILE64_OK)
if(NOT FILE64_OK)
# Test with _FILE_OFFSET_BITS=64
TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}"
"${CMAKE_SOURCE_DIR}/cmake/TestFileOffsetBits.c"
COMPILE_DEFINITIONS "-D_FILE_OFFSET_BITS=64" )
if(FILE64_OK)
MESSAGE(STATUS "Checking for 64-bit off_t - present with _FILE_OFFSET_BITS=64")
set(_FILE_OFFSET_BITS 64)
endif(FILE64_OK)
endif(NOT FILE64_OK)
if(NOT FILE64_OK)
# Test with _LARGE_FILES
TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}"
"${CMAKE_SOURCE_DIR}/cmake/TestFileOffsetBits.c"
COMPILE_DEFINITIONS "-D_LARGE_FILES" )
if(FILE64_OK)
MESSAGE(STATUS "Checking for 64-bit off_t - present with _LARGE_FILES")
set(_LARGE_FILES 1)
endif(FILE64_OK)
endif(NOT FILE64_OK)
if(NOT FILE64_OK)
# Test with _LARGEFILE_SOURCE
TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}"
"${CMAKE_SOURCE_DIR}/cmake/TestFileOffsetBits.c"
COMPILE_DEFINITIONS "-D_LARGEFILE_SOURCE" )
if(FILE64_OK)
MESSAGE(STATUS "Checking for 64-bit off_t - present with _LARGEFILE_SOURCE")
set(_LARGEFILE_SOURCE 1)
endif(FILE64_OK)
endif(NOT FILE64_OK)
if(NOT FILE64_OK)
MESSAGE(STATUS "Checking for 64-bit off_t - not present")
else(NOT FILE64_OK)
# Set the flags we might have determined to be required above
configure_file("${CMAKE_SOURCE_DIR}/cmake/TestLargeFiles.c.cmakein"
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.c")
MESSAGE(STATUS "Checking for fseeko/ftello")
# Test if ftello/fseeko are available
TRY_COMPILE(FSEEKO_COMPILE_OK "${PROJECT_BINARY_DIR}"
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.c")
if(FSEEKO_COMPILE_OK)
MESSAGE(STATUS "Checking for fseeko/ftello - present")
endif(FSEEKO_COMPILE_OK)
if(NOT FSEEKO_COMPILE_OK)
# glibc 2.2 neds _LARGEFILE_SOURCE for fseeko (but not 64-bit off_t...)
TRY_COMPILE(FSEEKO_COMPILE_OK "${PROJECT_BINARY_DIR}"
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.c"
COMPILE_DEFINITIONS "-D_LARGEFILE_SOURCE" )
if(FSEEKO_COMPILE_OK)
MESSAGE(STATUS "Checking for fseeko/ftello - present with _LARGEFILE_SOURCE")
set(_LARGEFILE_SOURCE 1)
endif(FSEEKO_COMPILE_OK)
endif(NOT FSEEKO_COMPILE_OK)
endif(NOT FILE64_OK)
if(FSEEKO_COMPILE_OK)
SET(${VARIABLE} 1 CACHE INTERNAL "Result of test for large file support" FORCE)
set(HAVE_FSEEKO 1)
else(FSEEKO_COMPILE_OK)
MESSAGE(STATUS "Checking for fseeko/ftello - not found")
SET(${VARIABLE} 0 CACHE INTERNAL "Result of test for large file support" FORCE)
endif(FSEEKO_COMPILE_OK)
ENDIF(NOT DEFINED ${VARIABLE})
ENDMACRO(TEST_LARGE_FILES VARIABLE)

View File

@@ -3,6 +3,11 @@
#ifndef TAGLIB_CONFIG_H
#define TAGLIB_CONFIG_H
/* Defined if required for large files support */
#cmakedefine _LARGE_FILES ${_LARGE_FILES}
#cmakedefine _LARGEFILE_SOURCE ${_LARGEFILE_SOURCE}
#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
/* Defined if your compiler supports some byte swap functions */
#cmakedefine HAVE_GCC_BYTESWAP 1
#cmakedefine HAVE_GLIBC_BYTESWAP 1
@@ -10,6 +15,20 @@
#cmakedefine HAVE_MAC_BYTESWAP 1
#cmakedefine HAVE_OPENBSD_BYTESWAP 1
/* Defined if your compiler supports some atomic operations */
#cmakedefine HAVE_STD_ATOMIC 1
#cmakedefine HAVE_GCC_ATOMIC 1
#cmakedefine HAVE_MAC_ATOMIC 1
#cmakedefine HAVE_WIN_ATOMIC 1
#cmakedefine HAVE_IA64_ATOMIC 1
/* Defined if your compiler supports shared_ptr */
#cmakedefine HAVE_STD_SMART_PTR 1
/* Defined if your compiler supports some safer version of vsprintf */
#cmakedefine HAVE_VSNPRINTF 1
#cmakedefine HAVE_VSPRINTF_S 1
/* Defined if your compiler supports ISO _strdup */
#cmakedefine HAVE_ISO_STRDUP 1

View File

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

View File

@@ -1,38 +1,41 @@
<!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">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<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="$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
<link href="taglib-api.css" rel="stylesheet" type="text/css">
</head>
<body>
<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>
<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">

395
doc/taglib-api.css Normal file
View File

@@ -0,0 +1,395 @@
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%;
}

BIN
doc/taglib.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -5,7 +5,6 @@ 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/
)
@@ -38,8 +37,7 @@ 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}
)
########### next target ###############
add_executable(inspect inspect.cpp)
target_link_libraries(inspect tag)

View File

@@ -23,16 +23,19 @@
*/
#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include "tbytevector.h"
#include "mpegfile.h"
#include "id3v2tag.h"
#include "id3v2frame.h"
#include "id3v2header.h"
#include "commentsframe.h"
#include "id3v1tag.h"
#include "apetag.h"
#include <tbytevector.h>
#include <mpegfile.h>
#include <id3v2tag.h>
#include <id3v2frame.h>
#include <id3v2header.h>
#include <id3v1tag.h>
#include <apetag.h>
using namespace std;
using namespace TagLib;
@@ -61,16 +64,9 @@ int main(int argc, char *argv[])
<< " bytes in tag"
<< endl;
const auto &frames = id3v2tag->frameList();
for(auto it = frames.begin(); it != frames.end(); it++) {
cout << (*it)->frameID();
if(auto comment = dynamic_cast<ID3v2::CommentsFrame *>(*it))
if(!comment->description().isEmpty())
cout << " [" << comment->description() << "]";
cout << " - \"" << (*it)->toString() << "\"" << endl;
}
ID3v2::FrameList::ConstIterator it = id3v2tag->frameList().begin();
for(; it != id3v2tag->frameList().end(); it++)
cout << (*it)->frameID() << " - \"" << (*it)->toString() << "\"" << endl;
}
else
cout << "file does not have a valid id3v2 tag" << endl;
@@ -96,8 +92,8 @@ int main(int argc, char *argv[])
cout << endl << "APE" << endl;
if(ape) {
const auto &items = ape->itemListMap();
for(auto it = items.begin(); it != items.end(); ++it)
for(APE::ItemListMap::ConstIterator it = ape->itemListMap().begin();
it != ape->itemListMap().end(); ++it)
{
if((*it).second.type() != APE::Item::Binary)
cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl;

48
examples/inspect.cpp Normal file
View File

@@ -0,0 +1,48 @@
/* Copyright (C) 2012 Lukas Lalinsky <lalinsky@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <iostream>
#include <stdlib.h>
#include <fileref.h>
#include <tfile.h>
using namespace std;
using namespace TagLib;
int main(int argc, char *argv[])
{
// process the command line args
for(int i = 1; i < argc; i++) {
cout << "******************** \"" << argv[i] << "\"********************" << endl;
FileRef f(argv[i]);
if(!f.isNull() && f.file()) {
cout << f.file()->toString().to8Bit(true) << endl;
}
}
}

View File

@@ -23,9 +23,8 @@
*/
#include <iostream>
#include "tstring.h"
#include "mpegfile.h"
#include <mpegfile.h>
#include <tstring.h>
using namespace TagLib;

View File

@@ -24,13 +24,12 @@
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <stdio.h>
#include "tpropertymap.h"
#include "tstringlist.h"
#include "tvariant.h"
#include "fileref.h"
#include "tag.h"
#include <fileref.h>
#include <tag.h>
#include <tpicturemap.h>
#include <tpropertymap.h>
using namespace std;
@@ -47,74 +46,46 @@ int main(int argc, char *argv[])
TagLib::Tag *tag = f.tag();
cout << "-- TAG (basic) --" << endl;
cout << "title - \"" << tag->title() << "\"" << endl;
cout << "artist - \"" << tag->artist() << "\"" << endl;
cout << "album - \"" << tag->album() << "\"" << endl;
cout << "year - \"" << tag->year() << "\"" << endl;
cout << "comment - \"" << tag->comment() << "\"" << endl;
cout << "track - \"" << tag->track() << "\"" << endl;
cout << "genre - \"" << tag->genre() << "\"" << endl;
cout << "title - \"" << tag->title() << "\"" << endl;
cout << "artist - \"" << tag->artist() << "\"" << endl;
cout << "album - \"" << tag->album() << "\"" << endl;
cout << "year - \"" << tag->year() << "\"" << endl;
cout << "comment - \"" << tag->comment() << "\"" << endl;
cout << "track - \"" << tag->track() << "\"" << endl;
cout << "genre - \"" << tag->genre() << "\"" << endl;
if(!tag->pictures().isEmpty())
cout << "pictures -" << tag->pictures() << endl;
TagLib::PropertyMap tags = f.properties();
if(!tags.isEmpty()) {
unsigned int longest = 0;
for(auto j = tags.cbegin(); j != tags.cend(); ++j) {
if (j->first.size() > longest) {
longest = j->first.size();
}
}
TagLib::PropertyMap tags = f.file()->properties();
cout << "-- TAG (properties) --" << endl;
for(auto j = tags.cbegin(); j != tags.cend(); ++j) {
for(auto k = j->second.begin(); k != j->second.end(); ++k) {
cout << left << std::setfill(' ') << std::setw(longest) << j->first << " - " << '"' << *k << '"' << endl;
}
unsigned int longest = 0;
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
if (i->first.size() > longest) {
longest = i->first.size();
}
}
TagLib::StringList names = f.complexPropertyKeys();
for(const auto &name : names) {
const auto& properties = f.complexProperties(name);
for(const auto &property : properties) {
cout << name << ":" << endl;
for(const auto &[key, value] : property) {
cout << " " << left << std::setfill(' ') << std::setw(11) << key << " - ";
if(value.type() == TagLib::Variant::ByteVector) {
cout << "(" << value.value<TagLib::ByteVector>().size() << " bytes)" << endl;
/* The picture could be extracted using:
ofstream picture;
TagLib::String fn(argv[i]);
int slashPos = fn.rfind('/');
int dotPos = fn.rfind('.');
if(slashPos >= 0 && dotPos > slashPos) {
fn = fn.substr(slashPos + 1, dotPos - slashPos - 1);
}
fn += ".jpg";
picture.open(fn.toCString(), ios_base::out | ios_base::binary);
picture << value.value<TagLib::ByteVector>();
picture.close();
*/
}
else {
cout << value << endl;
}
}
cout << "-- TAG (properties) --" << endl;
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl;
}
}
}
if(!f.isNull() && f.audioProperties()) {
TagLib::AudioProperties *properties = f.audioProperties();
int seconds = properties->lengthInSeconds() % 60;
int minutes = (properties->lengthInSeconds() - seconds) / 60;
int seconds = properties->length() % 60;
int minutes = (properties->length() - seconds) / 60;
cout << "-- AUDIO --" << endl;
cout << "bitrate - " << properties->bitrate() << endl;
cout << "sample rate - " << properties->sampleRate() << endl;
cout << "channels - " << properties->channels() << endl;
cout << "length - " << minutes << ":" << setfill('0') << setw(2) << right << seconds << endl;
cout << "length - " << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
}
}
return 0;

View File

@@ -23,9 +23,7 @@
*/
#include <stdio.h>
#include <string.h>
#include "tag_c.h"
#include <tag_c.h>
#ifndef FALSE
#define FALSE 0
@@ -34,16 +32,15 @@
int main(int argc, char *argv[])
{
int i;
int seconds;
int minutes;
TagLib_File *file;
TagLib_Tag *tag;
const TagLib_AudioProperties *properties;
taglib_set_strings_unicode(1);
taglib_set_strings_unicode(FALSE);
for(i = 1; i < argc; i++) {
TagLib_File *file;
TagLib_Tag *tag;
const TagLib_AudioProperties *properties;
char **propertiesMap;
char **complexKeys;
printf("******************** \"%s\" ********************\n", argv[i]);
file = taglib_file_new(argv[i]);
@@ -53,115 +50,21 @@ int main(int argc, char *argv[])
tag = taglib_file_tag(file);
properties = taglib_file_audioproperties(file);
propertiesMap = taglib_property_keys(file);
complexKeys = taglib_complex_property_keys(file);
if(tag != NULL) {
printf("-- TAG (basic) --\n");
printf("-- TAG --\n");
printf("title - \"%s\"\n", taglib_tag_title(tag));
printf("artist - \"%s\"\n", taglib_tag_artist(tag));
printf("album - \"%s\"\n", taglib_tag_album(tag));
printf("year - \"%u\"\n", taglib_tag_year(tag));
printf("year - \"%i\"\n", taglib_tag_year(tag));
printf("comment - \"%s\"\n", taglib_tag_comment(tag));
printf("track - \"%u\"\n", taglib_tag_track(tag));
printf("track - \"%i\"\n", taglib_tag_track(tag));
printf("genre - \"%s\"\n", taglib_tag_genre(tag));
}
if(propertiesMap != NULL) {
char **keyPtr = propertiesMap;
int longest = 0;
while(*keyPtr) {
int len = (int)strlen(*keyPtr++);
if(len > longest) {
longest = len;
}
}
keyPtr = propertiesMap;
printf("-- TAG (properties) --\n");
while(*keyPtr) {
char **valPtr;
char **propertyValues = valPtr = taglib_property_get(file, *keyPtr);
while(valPtr && *valPtr)
{
printf("%-*s - \"%s\"\n", longest, *keyPtr, *valPtr++);
}
taglib_property_free(propertyValues);
++keyPtr;
}
}
if(complexKeys != NULL) {
char **keyPtr = complexKeys;
while(*keyPtr) {
TagLib_Complex_Property_Attribute*** props =
taglib_complex_property_get(file, *keyPtr);
if(props != NULL) {
TagLib_Complex_Property_Attribute*** propPtr = props;
while(*propPtr) {
TagLib_Complex_Property_Attribute** attrPtr = *propPtr;
printf("%s:\n", *keyPtr);
while(*attrPtr) {
TagLib_Complex_Property_Attribute *attr = *attrPtr;
TagLib_Variant_Type type = attr->value.type;
printf(" %-11s - ", attr->key);
switch(type) {
case TagLib_Variant_Void:
printf("null\n");
break;
case TagLib_Variant_Bool:
printf("%s\n", attr->value.value.boolValue ? "true" : "false");
break;
case TagLib_Variant_Int:
printf("%d\n", attr->value.value.intValue);
break;
case TagLib_Variant_UInt:
printf("%u\n", attr->value.value.uIntValue);
break;
case TagLib_Variant_LongLong:
printf("%lld\n", attr->value.value.longLongValue);
break;
case TagLib_Variant_ULongLong:
printf("%llu\n", attr->value.value.uLongLongValue);
break;
case TagLib_Variant_Double:
printf("%f\n", attr->value.value.doubleValue);
break;
case TagLib_Variant_String:
printf("\"%s\"\n", attr->value.value.stringValue);
break;
case TagLib_Variant_StringList:
if(attr->value.value.stringListValue) {
char **strs = attr->value.value.stringListValue;
char **s = strs;
while(*s) {
if(s != strs) {
printf(" ");
}
printf("%s", *s++);
}
}
printf("\n");
break;
case TagLib_Variant_ByteVector:
printf("(%u bytes)\n", attr->value.size);
break;
}
++attrPtr;
}
++propPtr;
}
taglib_complex_property_free(props);
}
++keyPtr;
}
taglib_complex_property_free_keys(complexKeys);
}
if(properties != NULL) {
int seconds = taglib_audioproperties_length(properties) % 60;
int minutes = (taglib_audioproperties_length(properties) - seconds) / 60;
seconds = taglib_audioproperties_length(properties) % 60;
minutes = (taglib_audioproperties_length(properties) - seconds) / 60;
printf("-- AUDIO --\n");
printf("bitrate - %i\n", taglib_audioproperties_bitrate(properties));
@@ -170,7 +73,6 @@ int main(int argc, char *argv[])
printf("length - %i:%02i\n", minutes, seconds);
}
taglib_property_free(propertiesMap);
taglib_tag_free_strings();
taglib_file_free(file);
}

View File

@@ -22,22 +22,24 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <fstream>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include "tlist.h"
#include "tfile.h"
#include "tpropertymap.h"
#include "tvariant.h"
#include "fileref.h"
#include "tag.h"
#include <tlist.h>
#include <fileref.h>
#include <tfile.h>
#include <tpicturemap.h>
#include <tag.h>
#include <tpropertymap.h>
using namespace std;
@@ -72,7 +74,7 @@ void usage()
cout << " -R <tagname> <tagvalue>" << endl;
cout << " -I <tagname> <tagvalue>" << endl;
cout << " -D <tagname>" << endl;
cout << " -p <picturefile> <description> (\"\" \"\" to remove)" << endl;
cout << " -p <picture(jpg only, file between double quotes)>" << endl;
cout << endl;
exit(1);
@@ -82,14 +84,14 @@ void checkForRejectedProperties(const TagLib::PropertyMap &tags)
{ // stolen from tagreader.cpp
if(tags.size() > 0) {
unsigned int longest = 0;
for(auto i = tags.begin(); i != tags.end(); ++i) {
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
if(i->first.size() > longest) {
longest = i->first.size();
}
}
cout << "-- rejected TAGs (properties) --" << endl;
for(auto i = tags.begin(); i != tags.end(); ++i) {
for(auto j = i->second.begin(); j != i->second.end(); ++j) {
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl;
}
}
@@ -113,18 +115,19 @@ int main(int argc, char *argv[])
if(fileList.isEmpty())
usage();
int i = 1;
while(i < argc - 1) {
if(argv[argc-1][1] == 'p')
argc++;
for(int i = 1; i < argc - 1; i += 2) {
if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {
char field = argv[i][1];
TagLib::String value = argv[i + 1];
int numArgsConsumed = 2;
TagLib::List<TagLib::FileRef>::Iterator it;
for(it = fileList.begin(); it != fileList.end(); ++it) {
for(auto &f : fileList) {
TagLib::Tag *t = f.tag();
TagLib::Tag *t = (*it).tag();
switch (field) {
case 't':
@@ -151,76 +154,64 @@ int main(int argc, char *argv[])
case 'R':
case 'I':
if(i + 2 < argc) {
TagLib::PropertyMap map = f.properties();
TagLib::PropertyMap map = (*it).file()->properties ();
if(field == 'R') {
map.replace(value, TagLib::String(argv[i + 2]));
}
else {
map.insert(value, TagLib::String(argv[i + 2]));
}
numArgsConsumed = 3;
checkForRejectedProperties(f.setProperties(map));
++i;
checkForRejectedProperties((*it).file()->setProperties(map));
}
else {
usage();
}
break;
case 'D': {
TagLib::PropertyMap map = f.properties();
TagLib::PropertyMap map = (*it).file()->properties();
map.erase(value);
checkForRejectedProperties(f.setProperties(map));
checkForRejectedProperties((*it).file()->setProperties(map));
break;
}
case 'p': {
if(i + 2 < argc) {
numArgsConsumed = 3;
if(!value.isEmpty()) {
if(!isFile(value.toCString())) {
cout << value.toCString() << " not found." << endl;
return 1;
}
ifstream picture;
picture.open(value.toCString());
stringstream buffer;
buffer << picture.rdbuf();
picture.close();
TagLib::String buf(buffer.str());
TagLib::ByteVector data(buf.data(TagLib::String::Latin1));
TagLib::String mimeType = data.startsWith("\x89PNG\x0d\x0a\x1a\x0a")
? "image/png" : "image/jpeg";
TagLib::String description(argv[i + 2]);
f.setComplexProperties("PICTURE", {
{
{"data", data},
{"pictureType", "Front Cover"},
{"mimeType", mimeType},
{"description", description}
}
});
case 'p':
{
if(!isFile(value.toCString())) {
cout << value.toCString() << " not found." << endl;
return 1;
}
else {
// empty value, remove pictures
f.setComplexProperties("PICTURE", {});
ifstream picture;
picture.open(value.toCString());
stringstream buffer;
buffer << picture.rdbuf();
picture.close();
TagLib::String buf(buffer.str());
TagLib::ByteVector data(buf.data(TagLib::String::Latin1));
if(!data.find("JFIF")) {
cout << value.toCString() << " is not a JPEG." << endl;
return 1;
}
}
else {
usage();
TagLib::Picture pic(data,
TagLib::Picture::FrontCover,
"image/jpeg",
"Added with taglib");
TagLib::PictureMap picMap(pic);
t->setPictures(picMap);
}
break;
}
default:
usage();
break;
}
}
i += numArgsConsumed;
}
else
usage();
}
for(auto &f : fileList)
f.save();
TagLib::List<TagLib::FileRef>::ConstIterator it;
for(it = fileList.begin(); it != fileList.end(); ++it)
(*it).file()->save();
return 0;
}

View File

@@ -2,32 +2,22 @@
usage()
{
echo "usage: $0 [OPTIONS]"
echo "usage: $0 [OPTIONS]"
cat << EOH
options:
[--libs]
[--cflags]
[--version]
[--prefix]
[--libs]
[--cflags]
[--version]
[--prefix]
EOH
exit 1
exit 1;
}
# 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
prefix=${CMAKE_INSTALL_PREFIX}
exec_prefix=${CMAKE_INSTALL_PREFIX}
libdir=${LIB_INSTALL_DIR}
includedir=${INCLUDE_INSTALL_DIR}
flags=""
@@ -39,22 +29,22 @@ while test $# -gt 0
do
case $1 in
--libs)
flags="$flags -L$libdir -ltag@TAGLIB_INSTALL_SUFFIX@ @ZLIB_LIBRARIES_FLAGS@"
;;
flags="$flags -L$libdir -ltag"
;;
--cflags)
flags="$flags -I$includedir -I$includedir/taglib@TAGLIB_INSTALL_SUFFIX@"
;;
flags="$flags -I$includedir/taglib"
;;
--version)
echo @TAGLIB_LIB_VERSION_STRING@
;;
echo ${TAGLIB_LIB_VERSION_STRING}
;;
--prefix)
echo ${prefix:-@CMAKE_INSTALL_PREFIX@}
;;
*)
echo "$0: unknown option $1"
echo
usage
;;
echo $prefix
;;
*)
echo "$0: unknown option $1"
echo
usage
;;
esac
shift
done

View File

@@ -1,12 +0,0 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/taglib-targets.cmake")
set(TAGLIB_FOUND ${TagLib_FOUND})
set(TAGLIB_VERSION ${TagLib_VERSION})
check_required_components("TagLib")
if(NOT TARGET TagLib::TagLib)
add_library(TagLib::TagLib ALIAS TagLib::tag)
endif()

View File

@@ -1,35 +1,35 @@
@echo off
goto beginning
*
* It is what it is, you can do with it as you please.
*
* Just don't blame me if it teaches your computer to smoke!
*
* -Enjoy
* fh :)_~
*
:beginning
if /i "%1#" == "--libs#" goto doit
if /i "%1#" == "--cflags#" goto doit
if /i "%1#" == "--version#" goto doit
if /i "%1#" == "--prefix#" goto doit
echo usage: %0 [OPTIONS]
echo [--libs]
echo [--cflags]
echo [--version]
echo [--prefix]
goto theend
*
* NOTE: Windows does not assume libraries are prefixed with 'lib'.
* NOTE: If '-llibtag' is the last element, it is easily appended in the users installation/makefile process
* to allow for static, shared or debug builds.
* It would be preferable if the top level CMakeLists.txt provided the library name during config. ??
:doit
if /i "%1#" == "--libs#" echo -L${CMAKE_INSTALL_FULL_LIBDIR} -llibtag${TAGLIB_INSTALL_SUFFIX}
if /i "%1#" == "--cflags#" echo -I${CMAKE_INSTALL_FULL_INCLUDEDIR} -I${CMAKE_INSTALL_FULL_INCLUDEDIR}/taglib${TAGLIB_INSTALL_SUFFIX}
if /i "%1#" == "--version#" echo ${TAGLIB_LIB_VERSION_STRING}
if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX}
:theend
@echo off
goto beginning
*
* It is what it is, you can do with it as you please.
*
* Just don't blame me if it teaches your computer to smoke!
*
* -Enjoy
* fh :)_~
*
:beginning
if /i "%1#" == "--libs#" goto doit
if /i "%1#" == "--cflags#" goto doit
if /i "%1#" == "--version#" goto doit
if /i "%1#" == "--prefix#" goto doit
echo "usage: %0 [OPTIONS]"
echo [--libs]
echo [--cflags]
echo [--version]
echo [--prefix]
goto theend
*
* NOTE: Windows does not assume libraries are prefixed with 'lib'.
* NOTE: If '-llibtag' is the last element, it is easily appended in the users installation/makefile process
* to allow for static, shared or debug builds.
* It would be preferable if the top level CMakeLists.txt provided the library name during config. ??
:doit
if /i "%1#" == "--libs#" echo -L${LIB_INSTALL_DIR} -llibtag
if /i "%1#" == "--cflags#" echo -I${INCLUDE_INSTALL_DIR}/taglib
if /i "%1#" == "--version#" echo ${TAGLIB_LIB_VERSION_STRING}
if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX}
:theend

View File

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

View File

@@ -24,41 +24,49 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/s3m
${CMAKE_CURRENT_SOURCE_DIR}/it
${CMAKE_CURRENT_SOURCE_DIR}/xm
${CMAKE_CURRENT_SOURCE_DIR}/ebml
${CMAKE_CURRENT_SOURCE_DIR}/ebml/matroska
${CMAKE_CURRENT_SOURCE_DIR}/dsf
${CMAKE_CURRENT_SOURCE_DIR}/dsdiff
${CMAKE_SOURCE_DIR}/3rdparty
)
if(ZLIB_FOUND)
include_directories(${ZLIB_INCLUDE_DIR})
elseif(HAVE_ZLIB_SOURCE)
include_directories(${ZLIB_SOURCE})
endif()
set(tag_HDRS
tag.h
fileref.h
audioproperties.h
taglib_export.h
${CMAKE_CURRENT_BINARY_DIR}/../taglib_config.h
toolkit/taglib.h
toolkit/tstring.h
toolkit/tlist.h
toolkit/tlist.tcc
toolkit/tstringlist.h
toolkit/tstringhandler.h
toolkit/tbytevector.h
toolkit/tbytevectorlist.h
toolkit/tvariant.h
toolkit/tbytevectorstream.h
toolkit/tiostream.h
toolkit/tfile.h
toolkit/tfilestream.h
toolkit/tmap.h
toolkit/tmap.tcc
toolkit/tpicturetype.h
toolkit/tpicture.h
toolkit/tpicturemap.h
toolkit/tpropertymap.h
toolkit/trefcounter.h
toolkit/tdebuglistener.h
toolkit/tversionnumber.h
mpeg/mpegfile.h
mpeg/mpegproperties.h
mpeg/mpegheader.h
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
@@ -126,7 +134,6 @@ set(tag_HDRS
mp4/mp4item.h
mp4/mp4properties.h
mp4/mp4coverart.h
mp4/mp4itemfactory.h
mod/modfilebase.h
mod/modfile.h
mod/modtag.h
@@ -137,6 +144,12 @@ set(tag_HDRS
s3m/s3mproperties.h
xm/xmfile.h
xm/xmproperties.h
ebml/ebmlfile.h
ebml/ebmlelement.h
ebml/ebmlconstants.h
ebml/matroska/ebmlmatroskafile.h
ebml/matroska/ebmlmatroskaconstants.h
ebml/matroska/ebmlmatroskaaudio.h
dsf/dsffile.h
dsf/dsfproperties.h
dsdiff/dsdifffile.h
@@ -222,7 +235,6 @@ set(mp4_SRCS
mp4/mp4item.cpp
mp4/mp4properties.cpp
mp4/mp4coverart.cpp
mp4/mp4itemfactory.cpp
)
set(ape_SRCS
@@ -303,6 +315,16 @@ set(dsf_SRCS
dsf/dsfproperties.cpp
)
set(ebml_SRCS
ebml/ebmlfile.cpp
ebml/ebmlelement.cpp
)
set(matroska_SRCS
ebml/matroska/ebmlmatroskafile.cpp
ebml/matroska/ebmlmatroskaaudio.cpp
)
set(dsdiff_SRCS
dsdiff/dsdifffile.cpp
dsdiff/dsdiffproperties.cpp
@@ -310,29 +332,43 @@ set(dsdiff_SRCS
)
set(toolkit_SRCS
toolkit/taglib.cpp
toolkit/tstring.cpp
toolkit/tstringlist.cpp
toolkit/tstringhandler.cpp
toolkit/tbytevector.cpp
toolkit/tbytevectorlist.cpp
toolkit/tvariant.cpp
toolkit/tbytevectorstream.cpp
toolkit/tiostream.cpp
toolkit/tfile.cpp
toolkit/tfilestream.cpp
toolkit/tdebug.cpp
toolkit/tpicturetype.cpp
toolkit/tpicture.cpp
toolkit/tpicturemap.cpp
toolkit/tpropertymap.cpp
toolkit/trefcounter.cpp
toolkit/tdebuglistener.cpp
toolkit/tzlib.cpp
toolkit/tversionnumber.cpp
)
if(HAVE_ZLIB_SOURCE)
set(zlib_SRCS
${ZLIB_SOURCE}/adler32.c
${ZLIB_SOURCE}/crc32.c
${ZLIB_SOURCE}/inffast.c
${ZLIB_SOURCE}/inflate.c
${ZLIB_SOURCE}/inftrees.c
${ZLIB_SOURCE}/zutil.c
)
endif()
set(tag_LIB_SRCS
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${dsf_SRCS} ${dsdiff_SRCS}
${ebml_SRCS} ${matroska_SRCS} ${dsf_SRCS} ${dsdiff_SRCS}
${zlib_SRCS}
tag.cpp
tagunion.cpp
fileref.cpp
@@ -342,32 +378,26 @@ set(tag_LIB_SRCS
add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
target_include_directories(tag INTERFACE
$<INSTALL_INTERFACE:include>
$<INSTALL_INTERFACE:include/taglib${TAGLIB_INSTALL_SUFFIX}>
)
target_link_libraries(tag
PRIVATE $<$<TARGET_EXISTS:utf8::cpp>:utf8::cpp>
$<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB>
)
if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
target_link_libraries(tag ${ZLIB_LIBRARIES})
endif()
set_target_properties(tag PROPERTIES
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR}
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
DEFINE_SYMBOL MAKE_TAGLIB_LIB
INTERFACE_LINK_LIBRARIES "${ZLIB_INTERFACE_LINK_LIBRARIES}"
LINK_INTERFACE_LIBRARIES ""
PUBLIC_HEADER "${tag_HDRS}"
)
if(VISIBILITY_HIDDEN)
set_target_properties(tag PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(tag PROPERTIES CXX_VISIBILITY_PRESET hidden)
set_target_properties(tag PROPERTIES C_VISIBILITY_PRESET hidden
)
endif()
if(BUILD_FRAMEWORK)
unset(INSTALL_NAME_DIR)
set_target_properties(tag PROPERTIES
set_target_properties(tag PROPERTIES
FRAMEWORK TRUE
MACOSX_RPATH 1
VERSION "A"
@@ -375,43 +405,10 @@ if(BUILD_FRAMEWORK)
)
endif()
if(TAGLIB_INSTALL_SUFFIX)
if(BUILD_SHARED_LIBS)
set(TAGLIB_LIBRARY_SUFFIX "${TAGLIB_INSTALL_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}")
else()
set(TAGLIB_LIBRARY_SUFFIX "${TAGLIB_INSTALL_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()
set_target_properties(tag PROPERTIES SUFFIX ${TAGLIB_LIBRARY_SUFFIX})
endif()
install(TARGETS tag
EXPORT taglibTargets
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/taglib${TAGLIB_INSTALL_SUFFIX}
)
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/taglib-config.cmake.in"
"${PROJECT_BINARY_DIR}/taglib-config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/taglib${TAGLIB_INSTALL_SUFFIX}
)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/taglib-config-version.cmake"
VERSION "${TAGLIB_LIB_VERSION_STRING}"
COMPATIBILITY AnyNewerVersion
)
install(EXPORT taglibTargets
FILE taglib-targets.cmake
NAMESPACE TagLib::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/taglib${TAGLIB_INSTALL_SUFFIX}
)
install(FILES "${PROJECT_BINARY_DIR}/taglib-config.cmake"
"${PROJECT_BINARY_DIR}/taglib-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/taglib${TAGLIB_INSTALL_SUFFIX}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/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
items 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 i
tems to be sorted by importance / size, but this is not feasible. This
convention should only be broken when adding less important small items and it
is not desirable to rewrite the entire tag. An APE tag at the end of a file
(the recommended location) must have at least a footer; an APE tag at the

View File

@@ -31,14 +31,17 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "apefile.h"
#include <tbytevector.h>
#include <tstring.h>
#include <tdebug.h>
#include <tagunion.h>
#include <id3v1tag.h>
#include <id3v2header.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include <tsmartptr.h>
#include "tdebug.h"
#include "tpropertymap.h"
#include "id3v1tag.h"
#include "id3v2header.h"
#include "tagunion.h"
#include "tagutils.h"
#include "apefile.h"
#include "apetag.h"
#include "apefooter.h"
@@ -47,23 +50,30 @@ using namespace TagLib;
namespace
{
enum { ApeAPEIndex = 0, ApeID3v1Index = 1 };
} // namespace
}
class APE::File::FilePrivate
{
public:
offset_t APELocation { -1 };
long APESize { 0 };
FilePrivate() :
APELocation(-1),
APESize(0),
ID3v1Location(-1),
ID3v2Location(-1),
ID3v2Size(0) {}
offset_t ID3v1Location { -1 };
long long APELocation;
long long APESize;
std::unique_ptr<ID3v2::Header> ID3v2Header;
offset_t ID3v2Location { -1 };
long ID3v2Size { 0 };
long long ID3v1Location;
TagUnion tag;
SCOPED_PTR<ID3v2::Header> ID3v2Header;
long long ID3v2Location;
long long ID3v2Size;
std::unique_ptr<Properties> properties;
DoubleTagUnion tag;
SCOPED_PTR<AudioProperties> properties;
};
////////////////////////////////////////////////////////////////////////////////
@@ -75,46 +85,39 @@ 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);
return (buffer.find("MAC ") != ByteVector::npos());
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
APE::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) :
TagLib::File(file),
d(std::make_unique<FilePrivate>())
d(new FilePrivate())
{
if(isOpen())
read(readProperties);
}
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
APE::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) :
TagLib::File(stream),
d(std::make_unique<FilePrivate>())
d(new FilePrivate())
{
if(isOpen())
read(readProperties);
}
APE::File::~File() = default;
APE::File::~File()
{
delete d;
}
TagLib::Tag *APE::File::tag() const
{
return &d->tag;
}
PropertyMap APE::File::properties() const
{
return d->tag.properties();
}
void APE::File::removeUnsupportedProperties(const StringList &properties)
{
d->tag.removeUnsupportedProperties(properties);
}
PropertyMap APE::File::setProperties(const PropertyMap &properties)
{
if(ID3v1Tag())
@@ -123,7 +126,7 @@ PropertyMap APE::File::setProperties(const PropertyMap &properties)
return APETag(true)->setProperties(properties);
}
APE::Properties *APE::File::audioProperties() const
APE::AudioProperties *APE::File::audioProperties() const
{
return d->properties.get();
}
@@ -175,7 +178,7 @@ bool APE::File::save()
}
const ByteVector data = APETag()->render();
insert(data, d->APELocation, d->APESize);
insert(data, d->APELocation, static_cast<size_t>(d->APESize));
if(d->ID3v1Location >= 0)
d->ID3v1Location += (static_cast<long>(data.size()) - d->APESize);
@@ -187,7 +190,7 @@ bool APE::File::save()
// APE tag is empty. Remove the old one.
if(d->APELocation >= 0) {
removeBlock(d->APELocation, d->APESize);
removeBlock(d->APELocation, static_cast<size_t>(d->APESize));
if(d->ID3v1Location >= 0)
d->ID3v1Location -= d->APESize;
@@ -213,10 +216,10 @@ APE::Tag *APE::File::APETag(bool create)
void APE::File::strip(int tags)
{
if(tags & ID3v1)
d->tag.set(ApeID3v1Index, nullptr);
d->tag.set(ApeID3v1Index, 0);
if(tags & APE)
d->tag.set(ApeAPEIndex, nullptr);
d->tag.set(ApeAPEIndex, 0);
if(!ID3v1Tag())
APETag(true);
@@ -244,7 +247,7 @@ void APE::File::read(bool readProperties)
if(d->ID3v2Location >= 0) {
seek(d->ID3v2Location);
d->ID3v2Header = std::make_unique<ID3v2::Header>(readBlock(ID3v2::Header::size()));
d->ID3v2Header.reset(new ID3v2::Header(readBlock(ID3v2::Header::size())));
d->ID3v2Size = d->ID3v2Header->completeTagSize();
}
@@ -272,7 +275,7 @@ void APE::File::read(bool readProperties)
if(readProperties) {
offset_t streamLength;
long long streamLength;
if(d->APELocation >= 0)
streamLength = d->APELocation;
@@ -289,6 +292,6 @@ void APE::File::read(bool readProperties)
seek(0);
}
d->properties = std::make_unique<Properties>(this, streamLength);
d->properties.reset(new AudioProperties(this, streamLength));
}
}

View File

@@ -90,7 +90,7 @@ namespace TagLib {
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Constructs an APE file from \a stream. If \a readProperties is true the
@@ -102,47 +102,31 @@ namespace TagLib {
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Destroys this instance of the File.
*/
~File() override;
File(const File &) = delete;
File &operator=(const File &) = delete;
virtual ~File();
/*!
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
* or a combination of the two.
*/
TagLib::Tag *tag() const override;
/*!
* Implements the unified property interface -- export function.
* If the file contains both an APE and an ID3v1 tag, only APE
* will be converted to the PropertyMap.
*/
PropertyMap properties() const override;
/*!
* Removes unsupported properties. Forwards to the actual Tag's
* removeUnsupportedProperties() function.
*/
void removeUnsupportedProperties(const StringList &properties) override;
virtual TagLib::Tag *tag() const;
/*!
* Implements the unified property interface -- import function.
* Creates an APEv2 tag if necessary. A potentially existing ID3v1
* tag will be updated as well.
*/
PropertyMap setProperties(const PropertyMap &) override;
virtual PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the APE::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Properties *audioProperties() const override;
virtual AudioProperties *audioProperties() const;
/*!
* Saves the file.
@@ -150,7 +134,7 @@ namespace TagLib {
* \note According to the official Monkey's Audio SDK, an APE file
* can only have either ID3V1 or APE tags, so a parameter is used here.
*/
bool save() override;
virtual bool save();
/*!
* Returns a pointer to the ID3v1 tag of the file.
@@ -224,13 +208,15 @@ namespace TagLib {
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties);
class FilePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FilePrivate> d;
FilePrivate *d;
};
} // namespace APE
} // namespace TagLib
}
}
#endif

View File

@@ -24,25 +24,37 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "apefooter.h"
#include <iostream>
#include <bitset>
#include <tstring.h>
#include <tdebug.h>
#include "apefooter.h"
using namespace TagLib;
using namespace APE;
class APE::Footer::FooterPrivate
{
public:
unsigned int version { 0 };
FooterPrivate() :
version(0),
footerPresent(true),
headerPresent(false),
isHeader(false),
itemCount(0),
tagSize(0) {}
bool footerPresent { true };
bool headerPresent { false };
unsigned int version;
bool isHeader { false };
bool footerPresent;
bool headerPresent;
unsigned int itemCount { 0 };
unsigned int tagSize { 0 };
bool isHeader;
unsigned int itemCount;
unsigned int tagSize;
};
////////////////////////////////////////////////////////////////////////////////
@@ -64,17 +76,20 @@ ByteVector APE::Footer::fileIdentifier()
////////////////////////////////////////////////////////////////////////////////
APE::Footer::Footer() :
d(std::make_unique<FooterPrivate>())
d(new FooterPrivate())
{
}
APE::Footer::Footer(const ByteVector &data) :
d(std::make_unique<FooterPrivate>())
d(new FooterPrivate())
{
parse(data);
}
APE::Footer::~Footer() = default;
APE::Footer::~Footer()
{
delete d;
}
unsigned int APE::Footer::version() const
{
@@ -120,7 +135,8 @@ unsigned int APE::Footer::completeTagSize() const
{
if(d->headerPresent)
return d->tagSize + size();
return d->tagSize;
else
return d->tagSize;
}
void APE::Footer::setTagSize(unsigned int s)
@@ -142,7 +158,8 @@ ByteVector APE::Footer::renderHeader() const
{
if(!d->headerPresent)
return ByteVector();
return render(true);
else
return render(true);
}
////////////////////////////////////////////////////////////////////////////////
@@ -158,19 +175,19 @@ void APE::Footer::parse(const ByteVector &data)
// Read the version number
d->version = data.toUInt(8, false);
d->version = data.toUInt32LE(8);
// Read the tag size
d->tagSize = data.toUInt(12, false);
d->tagSize = data.toUInt32LE(12);
// Read the item count
d->itemCount = data.toUInt(16, false);
d->itemCount = data.toUInt32LE(16);
// Read the flags
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false)));
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt32LE(20)));
d->headerPresent = flags[31];
d->footerPresent = !flags[30];
@@ -189,15 +206,15 @@ ByteVector APE::Footer::render(bool isHeader) const
// add the version number -- we always render a 2.000 tag regardless of what
// the tag originally was.
v.append(ByteVector::fromUInt(2000, false));
v.append(ByteVector::fromUInt32LE(2000));
// add the tag size
v.append(ByteVector::fromUInt(d->tagSize, false));
v.append(ByteVector::fromUInt32LE(d->tagSize));
// add the item count
v.append(ByteVector::fromUInt(d->itemCount, false));
v.append(ByteVector::fromUInt32LE(d->itemCount));
// render and add the flags
@@ -207,11 +224,11 @@ ByteVector APE::Footer::render(bool isHeader) const
flags[30] = false; // footer is always present
flags[29] = isHeader;
v.append(ByteVector::fromUInt(static_cast<unsigned int>(flags.to_ulong()), false));
v.append(ByteVector::fromUInt32LE(flags.to_ulong()));
// add the reserved 64bit
v.append(ByteVector::fromLongLong(0));
v.append(ByteVector::fromUInt64BE(0));
return v;
}

View File

@@ -54,16 +54,13 @@ namespace TagLib {
* Constructs an APE footer based on \a data. parse() is called
* immediately.
*/
Footer(const ByteVector &data);
explicit Footer(const ByteVector &data);
/*!
* Destroys the footer.
*/
virtual ~Footer();
Footer(const Footer &) = delete;
Footer &operator=(const Footer &) = delete;
/*!
* Returns the version number. (Note: This is the 1000 or 2000.)
*/
@@ -163,12 +160,14 @@ namespace TagLib {
ByteVector render(bool isHeader) const;
private:
Footer(const Footer &);
Footer &operator=(const Footer &);
class FooterPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FooterPrivate> d;
FooterPrivate *d;
};
} // namespace APE
} // namespace TagLib
}
}
#endif

View File

@@ -23,24 +23,35 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevectorlist.h>
#include <tdebug.h>
#include <tsmartptr.h>
#include "apeitem.h"
#include <utility>
#include <numeric>
#include "tdebug.h"
using namespace TagLib;
using namespace APE;
class APE::Item::ItemPrivate
struct ItemData
{
public:
Item::ItemTypes type { Text };
ItemData() :
type(Item::Text),
readOnly(false) {}
Item::ItemTypes type;
String key;
ByteVector value;
StringList text;
bool readOnly { false };
bool readOnly;
};
class APE::Item::ItemPrivate
{
public:
ItemPrivate() :
data(new ItemData()) {}
SHARED_PTR<ItemData> data;
};
////////////////////////////////////////////////////////////////////////////////
@@ -48,36 +59,46 @@ public:
////////////////////////////////////////////////////////////////////////////////
APE::Item::Item() :
d(std::make_unique<ItemPrivate>())
d(new ItemPrivate())
{
}
APE::Item::Item(const String &key, const String &value) :
d(new ItemPrivate())
{
d->data->key = key;
d->data->text.append(value);
}
APE::Item::Item(const String &key, const StringList &values) :
d(std::make_unique<ItemPrivate>())
d(new ItemPrivate())
{
d->key = key;
d->text = values;
d->data->key = key;
d->data->text = values;
}
APE::Item::Item(const String &key, const ByteVector &value, bool binary) :
d(std::make_unique<ItemPrivate>())
d(new ItemPrivate())
{
d->key = key;
d->data->key = key;
if(binary) {
d->type = Binary;
d->value = value;
d->data->type = Binary;
d->data->value = value;
}
else {
d->text.append(value);
d->data->text.append(value);
}
}
APE::Item::Item(const Item &item) :
d(std::make_unique<ItemPrivate>(*item.d))
d(new ItemPrivate(*item.d))
{
}
APE::Item::~Item() = default;
APE::Item::~Item()
{
delete d;
}
Item &APE::Item::operator=(const Item &item)
{
@@ -85,7 +106,7 @@ Item &APE::Item::operator=(const Item &item)
return *this;
}
void APE::Item::swap(Item &item) noexcept
void APE::Item::swap(Item &item)
{
using std::swap;
@@ -94,117 +115,122 @@ void APE::Item::swap(Item &item) noexcept
void APE::Item::setReadOnly(bool readOnly)
{
d->readOnly = readOnly;
d->data->readOnly = readOnly;
}
bool APE::Item::isReadOnly() const
{
return d->readOnly;
return d->data->readOnly;
}
void APE::Item::setType(APE::Item::ItemTypes val)
{
d->type = val;
d->data->type = val;
}
APE::Item::ItemTypes APE::Item::type() const
{
return d->type;
return d->data->type;
}
String APE::Item::key() const
{
return d->key;
return d->data->key;
}
ByteVector APE::Item::binaryData() const
{
return d->value;
return d->data->value;
}
void APE::Item::setBinaryData(const ByteVector &value)
{
d->type = Binary;
d->value = value;
d->text.clear();
d->data->type = Binary;
d->data->value = value;
d->data->text.clear();
}
void APE::Item::setKey(const String &key)
{
d->key = key;
d->data->key = key;
}
void APE::Item::setValue(const String &value)
{
d->type = Text;
d->text = value;
d->value.clear();
d->data->type = Text;
d->data->text = value;
d->data->value.clear();
}
void APE::Item::setValues(const StringList &value)
{
d->type = Text;
d->text = value;
d->value.clear();
d->data->type = Text;
d->data->text = value;
d->data->value.clear();
}
void APE::Item::appendValue(const String &value)
{
d->type = Text;
d->text.append(value);
d->value.clear();
d->data->type = Text;
d->data->text.append(value);
d->data->value.clear();
}
void APE::Item::appendValues(const StringList &values)
{
d->type = Text;
d->text.append(values);
d->value.clear();
d->data->type = Text;
d->data->text.append(values);
d->data->value.clear();
}
int APE::Item::size() const
{
int result = 8 + d->key.size() + 1;
switch(d->type) {
size_t result = 8 + d->data->key.size() + 1;
switch(d->data->type) {
case Text:
if(!d->text.isEmpty()) {
result = std::accumulate(d->text.cbegin(), d->text.cend(), result,
[](int sz, const String &t) {
return sz + 1 + t.data(String::UTF8).size();
}) - 1;
if(!d->data->text.isEmpty()) {
StringList::ConstIterator it = d->data->text.begin();
result += it->data(String::UTF8).size();
it++;
for(; it != d->data->text.end(); ++it)
result += 1 + it->data(String::UTF8).size();
}
break;
case Binary:
case Locator:
result += d->value.size();
result += d->data->value.size();
break;
}
return result;
return static_cast<int>(result);
}
StringList APE::Item::values() const
{
return d->text;
return d->data->text;
}
String APE::Item::toString() const
{
if(d->type == Text && !isEmpty())
return d->text.front();
return String();
if(d->data->type == Text && !isEmpty())
return d->data->text.front();
else
return String();
}
bool APE::Item::isEmpty() const
{
switch(d->type) {
switch(d->data->type) {
case Text:
if(d->text.isEmpty())
if(d->data->text.isEmpty())
return true;
return d->text.size() == 1 && d->text.front().isEmpty();
if(d->data->text.size() == 1 && d->data->text.front().isEmpty())
return true;
return false;
case Binary:
case Locator:
return d->value.isEmpty();
return d->data->value.isEmpty();
default:
return false;
}
@@ -219,52 +245,53 @@ void APE::Item::parse(const ByteVector &data)
return;
}
const unsigned int valueLength = data.toUInt(0, false);
const unsigned int flags = data.toUInt(4, false);
const unsigned int valueLength = data.toUInt32LE(0);
const unsigned int flags = data.toUInt32LE(4);
// An item key can contain ASCII characters from 0x20 up to 0x7E, not UTF-8.
// We assume that the validity of the given key has been checked.
d->key = String(&data[8], String::Latin1);
d->data->key = String(&data[8], String::Latin1);
const ByteVector val = data.mid(8 + d->key.size() + 1, valueLength);
const ByteVector value = data.mid(8 + d->data->key.size() + 1, valueLength);
setReadOnly(flags & 1);
setType(static_cast<ItemTypes>((flags >> 1) & 3));
setType(ItemTypes((flags >> 1) & 3));
if(Text == d->type)
d->text = StringList(ByteVectorList::split(val, '\0'), String::UTF8);
if(Text == d->data->type)
d->data->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
else
d->value = val;
d->data->value = value;
}
ByteVector APE::Item::render() const
{
ByteVector data;
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
ByteVector val;
unsigned int flags = ((d->data->readOnly) ? 1 : 0) | (d->data->type << 1);
ByteVector value;
if(isEmpty())
return data;
if(d->type == Text) {
auto it = d->text.cbegin();
if(d->data->type == Text) {
StringList::ConstIterator it = d->data->text.begin();
val.append(it->data(String::UTF8));
for(it = std::next(it); it != d->text.cend(); ++it) {
val.append('\0');
val.append(it->data(String::UTF8));
value.append(it->data(String::UTF8));
it++;
for(; it != d->data->text.end(); ++it) {
value.append('\0');
value.append(it->data(String::UTF8));
}
d->value = val;
d->data->value = value;
}
else
val.append(d->value);
value.append(d->data->value);
data.append(ByteVector::fromUInt(val.size(), false));
data.append(ByteVector::fromUInt(flags, false));
data.append(d->key.data(String::Latin1));
data.append(ByteVector::fromUInt32LE(value.size()));
data.append(ByteVector::fromUInt32LE(flags));
data.append(d->data->key.data(String::Latin1));
data.append(ByteVector('\0'));
data.append(val);
data.append(value);
return data;
}

View File

@@ -31,7 +31,9 @@
#include "tstringlist.h"
namespace TagLib {
namespace APE {
//! An implementation of APE-items
/*!
@@ -56,6 +58,11 @@ namespace TagLib {
*/
Item();
/*!
* Constructs a text item with \a key and \a value.
*/
Item(const String &key, const String &value);
/*!
* Constructs a text item with \a key and \a values.
*/
@@ -85,7 +92,7 @@ namespace TagLib {
/*!
* Exchanges the content of this item by the content of \a item.
*/
void swap(Item &item) noexcept;
void swap(Item &item);
/*!
* Returns the key.
@@ -120,7 +127,7 @@ namespace TagLib {
* Sets the text value of the item to the list of values in \a value and clears
* any previous contents.
*
* \see values()
* \see toStringList()
*/
void setValues(const StringList &values);
@@ -134,7 +141,7 @@ namespace TagLib {
/*!
* Appends \a values to extend the current list of text values.
*
* \see values()
* \see toStringList()
*/
void appendValues(const StringList &values);
@@ -177,11 +184,11 @@ namespace TagLib {
bool isReadOnly() const;
/*!
* Sets the type of the item to \a val.
* Sets the type of the item to \a type.
*
* \see ItemTypes
*/
void setType(ItemTypes val);
void setType(ItemTypes type);
/*!
* Returns the type of the item.
@@ -195,10 +202,12 @@ namespace TagLib {
private:
class ItemPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<ItemPrivate> d;
ItemPrivate *d;
};
} // namespace APE
} // namespace TagLib
}
}
#endif

View File

@@ -27,71 +27,95 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "apeproperties.h"
#include <tstring.h>
#include <tdebug.h>
#include "tdebug.h"
#include "id3v2tag.h"
#include "apeproperties.h"
#include "apefile.h"
#include "apefooter.h"
#include "apetag.h"
#include "apefooter.h"
using namespace TagLib;
class APE::Properties::PropertiesPrivate
class APE::AudioProperties::PropertiesPrivate
{
public:
int length { 0 };
int bitrate { 0 };
int sampleRate { 0 };
int channels { 0 };
int version { 0 };
int bitsPerSample { 0 };
unsigned int sampleFrames { 0 };
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
version(0),
bitsPerSample(0),
sampleFrames(0) {}
int length;
int bitrate;
int sampleRate;
int channels;
int version;
int bitsPerSample;
unsigned int sampleFrames;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
APE::Properties::Properties(File *file, offset_t streamLength, ReadStyle style) :
AudioProperties(style),
d(std::make_unique<PropertiesPrivate>())
APE::AudioProperties::AudioProperties(File *file, long long streamLength, ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
read(file, streamLength);
}
APE::Properties::~Properties() = default;
APE::AudioProperties::~AudioProperties()
{
delete d;
}
int APE::Properties::lengthInMilliseconds() const
int APE::AudioProperties::length() const
{
return lengthInSeconds();
}
int APE::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int APE::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int APE::Properties::bitrate() const
int APE::AudioProperties::bitrate() const
{
return d->bitrate;
}
int APE::Properties::sampleRate() const
int APE::AudioProperties::sampleRate() const
{
return d->sampleRate;
}
int APE::Properties::channels() const
int APE::AudioProperties::channels() const
{
return d->channels;
}
int APE::Properties::version() const
int APE::AudioProperties::version() const
{
return d->version;
}
int APE::Properties::bitsPerSample() const
int APE::AudioProperties::bitsPerSample() const
{
return d->bitsPerSample;
}
unsigned int APE::Properties::sampleFrames() const
unsigned int APE::AudioProperties::sampleFrames() const
{
return d->sampleFrames;
}
@@ -107,29 +131,29 @@ namespace
if(header.size() < 6 || !header.startsWith("MAC "))
return -1;
return header.toUShort(4, false);
return header.toUInt16LE(4);
}
} // namespace
}
void APE::Properties::read(File *file, offset_t streamLength)
void APE::AudioProperties::read(File *file, long long streamLength)
{
// First, we assume that the file pointer is set at the first descriptor.
offset_t offset = file->tell();
int vers = headerVersion(file->readBlock(6));
long long offset = file->tell();
int version = headerVersion(file->readBlock(6));
// Next, we look for the descriptor.
if(vers < 0) {
if(version < 0) {
offset = file->find("MAC ", offset);
file->seek(offset);
vers = headerVersion(file->readBlock(6));
version = headerVersion(file->readBlock(6));
}
if(vers < 0) {
debug("APE::Properties::read() -- APE descriptor not found");
if(version < 0) {
debug("APE::AudioProperties::read() -- APE descriptor not found");
return;
}
d->version = vers;
d->version = version;
if(d->version >= 3980)
analyzeCurrent(file);
@@ -143,17 +167,17 @@ void APE::Properties::read(File *file, offset_t streamLength)
}
}
void APE::Properties::analyzeCurrent(File *file)
void APE::AudioProperties::analyzeCurrent(File *file)
{
// Read the descriptor
file->seek(2, File::Current);
const ByteVector descriptor = file->readBlock(44);
if(descriptor.size() < 44) {
debug("APE::Properties::analyzeCurrent() -- descriptor is too short.");
debug("APE::AudioProperties::analyzeCurrent() -- descriptor is too short.");
return;
}
const unsigned int descriptorBytes = descriptor.toUInt(0, false);
const unsigned int descriptorBytes = descriptor.toUInt32LE(0);
if((descriptorBytes - 52) > 0)
file->seek(descriptorBytes - 52, File::Current);
@@ -161,39 +185,39 @@ void APE::Properties::analyzeCurrent(File *file)
// Read the header
const ByteVector header = file->readBlock(24);
if(header.size() < 24) {
debug("APE::Properties::analyzeCurrent() -- MAC header is too short.");
debug("APE::AudioProperties::analyzeCurrent() -- MAC header is too short.");
return;
}
// Get the APE info
d->channels = header.toShort(18, false);
d->sampleRate = header.toUInt(20, false);
d->bitsPerSample = header.toShort(16, false);
d->channels = header.toUInt16LE(18);
d->sampleRate = header.toUInt32LE(20);
d->bitsPerSample = header.toUInt16LE(16);
const unsigned int totalFrames = header.toUInt(12, false);
const unsigned int totalFrames = header.toUInt32LE(12);
if(totalFrames == 0)
return;
const unsigned int blocksPerFrame = header.toUInt(4, false);
const unsigned int finalFrameBlocks = header.toUInt(8, false);
const unsigned int blocksPerFrame = header.toUInt32LE(4);
const unsigned int finalFrameBlocks = header.toUInt32LE(8);
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
}
void APE::Properties::analyzeOld(File *file)
void APE::AudioProperties::analyzeOld(File *file)
{
const ByteVector header = file->readBlock(26);
if(header.size() < 26) {
debug("APE::Properties::analyzeOld() -- MAC header is too short.");
debug("APE::AudioProperties::analyzeOld() -- MAC header is too short.");
return;
}
const unsigned int totalFrames = header.toUInt(18, false);
const unsigned int totalFrames = header.toUInt32LE(18);
// Fail on 0 length APE files (catches non-finalized APE files)
if(totalFrames == 0)
return;
const short compressionLevel = header.toShort(0, false);
const short compressionLevel = header.toUInt32LE(0);
unsigned int blocksPerFrame;
if(d->version >= 3950)
blocksPerFrame = 73728 * 4;
@@ -203,19 +227,19 @@ void APE::Properties::analyzeOld(File *file)
blocksPerFrame = 9216;
// Get the APE info
d->channels = header.toShort(4, false);
d->sampleRate = header.toUInt(6, false);
d->channels = header.toUInt16LE(4);
d->sampleRate = header.toUInt32LE(6);
const unsigned int finalFrameBlocks = header.toUInt(22, false);
const unsigned int finalFrameBlocks = header.toUInt32LE(22);
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
// Get the bit depth from the RIFF-fmt chunk.
file->seek(16, File::Current);
const ByteVector fmt = file->readBlock(28);
if(fmt.size() < 28 || !fmt.startsWith("WAVEfmt ")) {
debug("APE::Properties::analyzeOld() -- fmt header is too short.");
debug("APE::AudioProperties::analyzeOld() -- fmt header is too short.");
return;
}
d->bitsPerSample = fmt.toShort(26, false);
d->bitsPerSample = fmt.toUInt16LE(26);
}

View File

@@ -30,7 +30,6 @@
#ifndef TAGLIB_APEPROPERTIES_H
#define TAGLIB_APEPROPERTIES_H
#include "taglib.h"
#include "taglib_export.h"
#include "audioproperties.h"
@@ -47,44 +46,59 @@ namespace TagLib {
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
public:
/*!
* Create an instance of APE::Properties with the data read from the
* APE::File \a file.
*/
Properties(File *file, offset_t streamLength, ReadStyle style = Average);
AudioProperties(File *file, long long streamLength, ReadStyle style = Average);
/*!
* Destroys this APE::Properties instance.
* Destroys this APE::AudioProperties instance.
*/
~Properties() override;
virtual ~AudioProperties();
Properties(const Properties &) = delete;
Properties &operator=(const Properties &) = delete;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
virtual int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
int lengthInMilliseconds() const override;
virtual int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
int bitrate() const override;
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
int sampleRate() const override;
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
int channels() const override;
virtual int channels() const;
/*!
* Returns the number of bits per audio sample.
@@ -102,16 +116,14 @@ namespace TagLib {
int version() const;
private:
void read(File *file, offset_t streamLength);
void read(File *file, long long streamLength);
void analyzeCurrent(File *file);
void analyzeOld(File *file);
class PropertiesPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<PropertiesPrivate> d;
PropertiesPrivate *d;
};
} // namespace APE
} // namespace TagLib
}
}
#endif

View File

@@ -31,14 +31,15 @@
#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
#endif
#include <tfile.h>
#include <tstring.h>
#include <tmap.h>
#include <tpicturemap.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <tutils.h>
#include "apetag.h"
#include <array>
#include <utility>
#include "tdebug.h"
#include "tfile.h"
#include "tpropertymap.h"
#include "apefooter.h"
#include "apeitem.h"
@@ -50,26 +51,37 @@ namespace
const unsigned int MinKeyLength = 2;
const unsigned int MaxKeyLength = 255;
const String FRONT_COVER("COVER ART (FRONT)");
const String BACK_COVER("COVER ART (BACK)");
bool isKeyValid(const ByteVector &key)
{
static constexpr std::array invalidKeys { "ID3", "TAG", "OGGS", "MP+" };
const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };
// only allow printable ASCII including space (32..126)
return std::none_of(key.begin(), key.end(),
[](unsigned char c) { return c < 32 || c > 126; })
&& std::none_of(invalidKeys.begin(), invalidKeys.end(),
[upperKey = String(key).upper()](auto k) { return upperKey == k; });
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(upperKey == invalidKeys[i])
return false;
}
return true;
}
} // namespace
}
class APE::Tag::TagPrivate
{
public:
File *file { nullptr };
offset_t footerLocation { 0 };
TagPrivate() :
file(0),
footerLocation(0) {}
File *file;
long long footerLocation;
Footer footer;
ItemListMap itemListMap;
@@ -80,12 +92,14 @@ public:
////////////////////////////////////////////////////////////////////////////////
APE::Tag::Tag() :
d(std::make_unique<TagPrivate>())
TagLib::Tag(),
d(new TagPrivate())
{
}
APE::Tag::Tag(TagLib::File *file, offset_t footerLocation) :
d(std::make_unique<TagPrivate>())
APE::Tag::Tag(TagLib::File *file, long long footerLocation) :
TagLib::Tag(),
d(new TagPrivate())
{
d->file = file;
d->footerLocation = footerLocation;
@@ -93,7 +107,10 @@ APE::Tag::Tag(TagLib::File *file, offset_t footerLocation) :
read();
}
APE::Tag::~Tag() = default;
APE::Tag::~Tag()
{
delete d;
}
ByteVector APE::Tag::fileIdentifier()
{
@@ -102,44 +119,87 @@ ByteVector APE::Tag::fileIdentifier()
String APE::Tag::title() const
{
Item val = d->itemListMap.value("TITLE");
return val.isEmpty() ? String() : joinTagValues(val.values());
if(d->itemListMap["TITLE"].isEmpty())
return String();
return d->itemListMap["TITLE"].values().toString();
}
String APE::Tag::artist() const
{
Item val = d->itemListMap.value("ARTIST");
return val.isEmpty() ? String() : joinTagValues(val.values());
if(d->itemListMap["ARTIST"].isEmpty())
return String();
return d->itemListMap["ARTIST"].values().toString();
}
String APE::Tag::album() const
{
Item val = d->itemListMap.value("ALBUM");
return val.isEmpty() ? String() : joinTagValues(val.values());
if(d->itemListMap["ALBUM"].isEmpty())
return String();
return d->itemListMap["ALBUM"].values().toString();
}
String APE::Tag::comment() const
{
Item val = d->itemListMap.value("COMMENT");
return val.isEmpty() ? String() : joinTagValues(val.values());
if(d->itemListMap["COMMENT"].isEmpty())
return String();
return d->itemListMap["COMMENT"].values().toString();
}
String APE::Tag::genre() const
{
Item val = d->itemListMap.value("GENRE");
return val.isEmpty() ? String() : joinTagValues(val.values());
if(d->itemListMap["GENRE"].isEmpty())
return String();
return d->itemListMap["GENRE"].values().toString();
}
unsigned int APE::Tag::year() const
{
Item val = d->itemListMap.value("YEAR");
return val.isEmpty() ? 0 : val.toString().toInt();
if(d->itemListMap["YEAR"].isEmpty())
return 0;
return d->itemListMap["YEAR"].toString().toInt();
}
unsigned int APE::Tag::track() const
{
Item val = d->itemListMap.value("TRACK");
return val.isEmpty() ? 0 : val.toString().toInt();
if(d->itemListMap["TRACK"].isEmpty())
return 0;
return d->itemListMap["TRACK"].toString().toInt();
}
TagLib::PictureMap APE::Tag::pictures() const
{
PictureMap map;
if(d->itemListMap.contains(FRONT_COVER)) {
Item front = d->itemListMap[FRONT_COVER];
if(Item::Binary == front.type()) {
ByteVector picture = front.binaryData();
const size_t index = picture.find('\0');
if(index < picture.size()) {
ByteVector desc = picture.mid(0, index + 1);
String mime = "image/jpeg";
ByteVector data = picture.mid(index + 1);
Picture p(data, Picture::FrontCover, mime, desc);
map.insert(p);
}
}
}
if(d->itemListMap.contains(BACK_COVER)) {
Item back = d->itemListMap[BACK_COVER];
if(Item::Binary == back.type()) {
ByteVector picture = back.binaryData();
const size_t index = picture.find('\0');
if(index < picture.size()) {
ByteVector desc = picture.mid(0, index + 1);
String mime = "image/jpeg";
ByteVector data = picture.mid(index + 1);
Picture p(data, Picture::BackCover, mime, desc);
map.insert(p);
}
}
}
return PictureMap(map);
}
void APE::Tag::setTitle(const String &s)
@@ -183,39 +243,94 @@ void APE::Tag::setTrack(unsigned int i)
addValue("TRACK", String::number(i), true);
}
void APE::Tag::setPictures(const PictureMap &l)
{
removeItem(FRONT_COVER);
removeItem(BACK_COVER);
for(PictureMap::ConstIterator pictureMapIt = l.begin();
pictureMapIt != l.end();
++pictureMapIt) {
Picture::Type type = pictureMapIt->first;
if(Picture::FrontCover != type && Picture::BackCover != type) {
std::cout << "APE: Trying to add a picture with wrong type"
<< std::endl;
continue;
}
const char *id;
switch(type) {
case Picture::FrontCover:
id = FRONT_COVER;
break;
case Picture::BackCover:
id = BACK_COVER;
break;
default:
id = FRONT_COVER;
break;
}
PictureList list = pictureMapIt->second;
for(PictureList::ConstIterator pictureListIt = list.begin();
pictureListIt != list.end();
++pictureListIt) {
Picture picture = *pictureListIt;
if(d->itemListMap.contains(id)) {
std::cout << "APE: Already added a picture of type "
<< id
<< " '"
<< picture.description()
<< "' "
<< "and next are being ignored"
<< std::endl;
break;
}
ByteVector data = picture.description().data(String::Latin1)
.append('\0')
.append(picture.data());
Item item;
item.setKey(id);
item.setType(Item::Binary);
item.setBinaryData(data);
setItem(item.key(), item);
}
}
}
namespace
{
// conversions of tag keys between what we use in PropertyMap and what's usual
// for APE tags
// usual, APE
constexpr std::array keyConversions {
std::pair("TRACKNUMBER", "TRACK"),
std::pair("DATE", "YEAR"),
std::pair("ALBUMARTIST", "ALBUM ARTIST"),
std::pair("DISCNUMBER", "DISC"),
std::pair("REMIXER", "MIXARTIST"),
std::pair("RELEASESTATUS", "MUSICBRAINZ_ALBUMSTATUS"),
std::pair("RELEASETYPE", "MUSICBRAINZ_ALBUMTYPE"),
};
} // namespace
// usual, APE
const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
{"DATE", "YEAR" },
{"ALBUMARTIST", "ALBUM ARTIST"},
{"DISCNUMBER", "DISC" },
{"REMIXER", "MIXARTIST" }};
const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]);
}
PropertyMap APE::Tag::properties() const
{
PropertyMap properties;
for(const auto &[tag, item] : std::as_const(itemListMap())) {
String tagName = tag.upper();
ItemListMap::ConstIterator it = itemListMap().begin();
for(; it != itemListMap().end(); ++it) {
String tagName = it->first.upper();
// if the item is Binary or Locator, or if the key is an invalid string,
// add to unsupportedData
if(item.type() != Item::Text || tagName.isEmpty()) {
properties.addUnsupportedData(tag);
if(it->second.type() != Item::Text || tagName.isEmpty()) {
properties.unsupportedData().append(it->first);
}
else {
// Some tags need to be handled specially
for(const auto &[k, t] : keyConversions) {
if(tagName == t)
tagName = k;
for(size_t i = 0; i < keyConversionsSize; ++i) {
if(tagName == keyConversions[i][1])
tagName = keyConversions[i][0];
}
properties[tagName].append(item.values());
properties[tagName].append(it->second.values());
}
}
return properties;
@@ -223,141 +338,57 @@ PropertyMap APE::Tag::properties() const
void APE::Tag::removeUnsupportedProperties(const StringList &properties)
{
for(const auto &property : properties)
removeItem(property);
StringList::ConstIterator it = properties.begin();
for(; it != properties.end(); ++it)
removeItem(*it);
}
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap props(origProps); // make a local copy that can be modified
PropertyMap properties(origProps); // make a local copy that can be modified
// see comment in properties()
for(const auto &[k, t] : keyConversions)
if(props.contains(k)) {
props.insert(t, props[k]);
props.erase(k);
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]);
}
// first check if tags need to be removed completely
StringList toRemove;
for(const auto &[k, t] : std::as_const(itemListMap())) {
String key = k.upper();
ItemListMap::ConstIterator remIt = itemListMap().begin();
for(; remIt != itemListMap().end(); ++remIt) {
String key = remIt->first.upper();
// only remove if a) key is valid, b) type is text, c) key not contained in new properties
if(!key.isEmpty() && t.type() == APE::Item::Text && !props.contains(key))
toRemove.append(k);
if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
toRemove.append(remIt->first);
}
for(const auto &item : std::as_const(toRemove))
removeItem(item);
for(StringList::ConstIterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
removeItem(*removeIt);
// now sync in the "forward direction"
PropertyMap::ConstIterator it = properties.begin();
PropertyMap invalid;
for(const auto &[tagName, val] : std::as_const(props)) {
for(; it != properties.end(); ++it) {
const String &tagName = it->first;
if(!checkKey(tagName))
invalid.insert(tagName, val);
else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == val)) {
if(val.isEmpty())
invalid.insert(it->first, it->second);
else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
if(it->second.isEmpty())
removeItem(tagName);
else {
addValue(tagName, *val.begin(), true);
for(auto it = std::next(val.begin()); it != val.end(); ++it)
addValue(tagName, *it, false);
StringList::ConstIterator valueIt = it->second.begin();
addValue(tagName, *valueIt, true);
++valueIt;
for(; valueIt != it->second.end(); ++valueIt)
addValue(tagName, *valueIt, false);
}
}
}
return invalid;
}
StringList APE::Tag::complexPropertyKeys() const
{
StringList keys;
if(d->itemListMap.contains(FRONT_COVER) ||
d->itemListMap.contains(BACK_COVER)) {
keys.append("PICTURE");
}
return keys;
}
List<VariantMap> APE::Tag::complexProperties(const String &key) const
{
List<VariantMap> props;
const String uppercaseKey = key.upper();
if(uppercaseKey == "PICTURE") {
const StringList itemNames = StringList(FRONT_COVER).append(BACK_COVER);
for(const auto &itemName: itemNames) {
if(d->itemListMap.contains(itemName)) {
Item picture = d->itemListMap.value(itemName);
if(picture.type() == Item::Binary) {
ByteVector data = picture.binaryData();
// Do not search for a description if the first byte could start JPG or PNG
// data.
int index = data.isEmpty() || data.at(0) == '\xff' || data.at(0) == '\x89'
? -1 : data.find('\0');
String description;
if(index >= 0) {
description = String(data.mid(0, index), String::UTF8);
data = data.mid(index + 1);
}
VariantMap property;
property.insert("data", data);
if(!description.isEmpty()) {
property.insert("description", description);
}
property.insert("pictureType",
itemName == BACK_COVER ? "Back Cover" : "Front Cover");
props.append(property);
}
}
}
}
return props;
}
bool APE::Tag::setComplexProperties(const String &key, const List<VariantMap> &value)
{
const String uppercaseKey = key.upper();
if(uppercaseKey == "PICTURE") {
removeItem(FRONT_COVER);
removeItem(BACK_COVER);
auto frontItems = List<Item>();
auto backItems = List<Item>();
for(const auto &property : value) {
auto data = property.value("description").value<String>().data(String::UTF8)
.append('\0')
.append(property.value("data").value<ByteVector>());
auto pictureType = property.value("pictureType").value<String>();
Item item;
item.setType(Item::Binary);
item.setBinaryData(data);
if(pictureType == "Back Cover") {
item.setKey(BACK_COVER);
backItems.append(item);
}
else if(pictureType == "Front Cover") {
item.setKey(FRONT_COVER);
// prioritize pictures with correct type
frontItems.prepend(item);
}
else {
item.setKey(FRONT_COVER);
frontItems.append(item);
}
}
if(!frontItems.isEmpty()) {
setItem(FRONT_COVER, frontItems.front());
}
if(!backItems.isEmpty()) {
setItem(BACK_COVER, backItems.front());
}
}
else {
return false;
}
return true;
}
bool APE::Tag::checkKey(const String &key)
{
if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
@@ -392,7 +423,7 @@ void APE::Tag::addValue(const String &key, const String &value, bool replace)
// Text items may contain more than one value.
// Binary or locator items may have only one value, hence always replaced.
auto it = d->itemListMap.find(key.upper());
ItemListMap::Iterator it = d->itemListMap.find(key.upper());
if(it != d->itemListMap.end() && it->second.type() == Item::Text)
it->second.appendValue(value);
@@ -450,13 +481,13 @@ ByteVector APE::Tag::render() const
ByteVector data;
unsigned int itemCount = 0;
for(const auto &[_, list] : std::as_const(d->itemListMap)) {
data.append(list.render());
for(ItemListMap::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) {
data.append(it->second.render());
itemCount++;
}
d->footer.setItemCount(itemCount);
d->footer.setTagSize(data.size() + Footer::size());
d->footer.setTagSize(static_cast<unsigned int>(data.size() + Footer::size()));
d->footer.setHeaderPresent(true);
return d->footer.renderHeader() + data + d->footer.renderFooter();
@@ -469,23 +500,18 @@ void APE::Tag::parse(const ByteVector &data)
if(data.size() < 11)
return;
unsigned int pos = 0;
size_t pos = 0;
for(unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
const int nullPos = data.find('\0', pos + 8);
if(nullPos < 0) {
const size_t nullPos = data.find('\0', pos + 8);
if(nullPos == ByteVector::npos()) {
debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing.");
return;
}
const unsigned int keyLength = nullPos - pos - 8;
const unsigned int valLength = data.toUInt(pos, false);
if(valLength >= data.size() || pos > data.size() - valLength) {
debug("APE::Tag::parse() - Invalid val length. Stopped parsing.");
return;
}
const size_t keyLength = nullPos - pos - 8;
const size_t valLegnth = data.toUInt32LE(pos);
if(keyLength >= MinKeyLength
&& keyLength <= MaxKeyLength
@@ -500,6 +526,6 @@ void APE::Tag::parse(const ByteVector &data)
debug("APE::Tag::parse() - Skipped an item due to an invalid key.");
}
pos += keyLength + valLength + 9;
pos += keyLength + valLegnth + 9;
}
}

View File

@@ -26,13 +26,17 @@
#ifndef TAGLIB_APETAG_H
#define TAGLIB_APETAG_H
#include "tag.h"
#include "tbytevector.h"
#include "tmap.h"
#include "tstring.h"
#include "taglib_export.h"
#include "tag.h"
#include "apeitem.h"
#define FRONT_COVER "COVER ART (FRONT)"
#define BACK_COVER "COVER ART (BACK)"
namespace TagLib {
class File;
@@ -48,7 +52,8 @@ namespace TagLib {
*
* \see APE::Tag::itemListMap()
*/
using ItemListMap = Map<const String, Item>;
typedef Map<String, Item> ItemListMap;
//! An APE tag implementation
@@ -64,15 +69,12 @@ namespace TagLib {
* Create an APE tag and parse the data in \a file with APE footer at
* \a tagOffset.
*/
Tag(TagLib::File *file, offset_t footerLocation);
Tag(TagLib::File *file, long long footerLocation);
/*!
* Destroys this Tag instance.
*/
~Tag() override;
Tag(const Tag &) = delete;
Tag &operator=(const Tag &) = delete;
virtual ~Tag();
/*!
* Renders the in memory values to a ByteVector suitable for writing to
@@ -88,21 +90,31 @@ namespace TagLib {
// Reimplementations.
String title() const override;
String artist() const override;
String album() const override;
String comment() const override;
String genre() const override;
unsigned int year() const override;
unsigned int track() const override;
virtual String title() const;
virtual String artist() const;
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual unsigned int year() const;
virtual unsigned int track() const;
void setTitle(const String &s) override;
void setArtist(const String &s) override;
void setAlbum(const String &s) override;
void setComment(const String &s) override;
void setGenre(const String &s) override;
void setYear(unsigned int i) override;
void setTrack(unsigned int i) override;
/**
* @brief pictures
* According to :
* http://www.hydrogenaud.io/forums/index.php?showtopic=40603&st=50&p=504669&#entry504669
* http://git.videolan.org/?p=vlc.git;a=blob;f=modules/meta_engine/taglib.cpp
* @return
*/
virtual PictureMap pictures() const;
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(unsigned int i);
virtual void setTrack(unsigned int i);
virtual void setPictures(const PictureMap &l);
/*!
* Implements the unified tag dictionary interface -- export function.
@@ -118,9 +130,9 @@ namespace TagLib {
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively,
* in order to be compliant with the names used in other formats.
*/
PropertyMap properties() const override;
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties) override;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified tag dictionary interface -- import function. The same
@@ -128,11 +140,7 @@ namespace TagLib {
* specification requires keys to have between 2 and 16 printable ASCII characters
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
*/
PropertyMap setProperties(const PropertyMap &) override;
StringList complexPropertyKeys() const override;
List<VariantMap> complexProperties(const String &key) const override;
bool setComplexProperties(const String &key, const List<VariantMap> &value) override;
PropertyMap setProperties(const PropertyMap &);
/*!
* Check if the given String is a valid APE tag key.
@@ -186,7 +194,7 @@ namespace TagLib {
/*!
* Returns true if the tag does not contain any data.
*/
bool isEmpty() const override;
bool isEmpty() const;
protected:
@@ -201,11 +209,13 @@ namespace TagLib {
void parse(const ByteVector &data);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<TagPrivate> d;
TagPrivate *d;
};
} // namespace APE
} // namespace TagLib
}
}
#endif

View File

@@ -1,4 +1,4 @@
/**************************************************************************
/**************************************************************************
copyright : (C) 2005-2007 by Lukáš Lalinský
email : lalinsky@gmail.com
**************************************************************************/
@@ -23,29 +23,45 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <taglib.h>
#include <tdebug.h>
#include <tsmartptr.h>
#include "asfattribute.h"
#include "tdebug.h"
#include "asffile.h"
#include "asfutils.h"
using namespace TagLib;
namespace
{
struct AttributeData
{
AttributeData() :
numericValue(0),
stream(0),
language(0) {}
ASF::Attribute::AttributeTypes type;
String stringValue;
ByteVector byteVectorValue;
ASF::Picture pictureValue;
unsigned long long numericValue;
int stream;
int language;
};
}
class ASF::Attribute::AttributePrivate
{
public:
AttributePrivate() :
pictureValue(ASF::Picture::fromInvalid())
data(new AttributeData())
{
data->pictureValue = ASF::Picture::fromInvalid();
}
AttributeTypes type;
String stringValue;
ByteVector byteVectorValue;
ASF::Picture pictureValue;
unsigned long long numericValue { 0 };
int stream { 0 };
int language { 0 };
SHARED_PTR<AttributeData> data;
};
////////////////////////////////////////////////////////////////////////////////
@@ -53,125 +69,136 @@ public:
////////////////////////////////////////////////////////////////////////////////
ASF::Attribute::Attribute() :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = UnicodeType;
d->data->type = UnicodeType;
}
ASF::Attribute::Attribute(const ASF::Attribute &) = default;
ASF::Attribute::Attribute(const ASF::Attribute &other) :
d(new AttributePrivate(*other.d))
{
}
ASF::Attribute::Attribute(const String &value) :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = UnicodeType;
d->stringValue = value;
d->data->type = UnicodeType;
d->data->stringValue = value;
}
ASF::Attribute::Attribute(const ByteVector &value) :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = BytesType;
d->byteVectorValue = value;
d->data->type = BytesType;
d->data->byteVectorValue = value;
}
ASF::Attribute::Attribute(const ASF::Picture &value) :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = BytesType;
d->pictureValue = value;
d->data->type = BytesType;
d->data->pictureValue = value;
}
ASF::Attribute::Attribute(unsigned int value) :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = DWordType;
d->numericValue = value;
d->data->type = DWordType;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(unsigned long long value) :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = QWordType;
d->numericValue = value;
d->data->type = QWordType;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(unsigned short value) :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = WordType;
d->numericValue = value;
d->data->type = WordType;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(bool value) :
d(std::make_shared<AttributePrivate>())
d(new AttributePrivate())
{
d->type = BoolType;
d->numericValue = value;
d->data->type = BoolType;
d->data->numericValue = value;
}
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &) = default;
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
{
Attribute(other).swap(*this);
return *this;
}
void ASF::Attribute::swap(Attribute &other) noexcept
void ASF::Attribute::swap(Attribute &other)
{
using std::swap;
swap(d, other.d);
}
ASF::Attribute::~Attribute() = default;
ASF::Attribute::~Attribute()
{
delete d;
}
ASF::Attribute::AttributeTypes ASF::Attribute::type() const
{
return d->type;
return d->data->type;
}
String ASF::Attribute::toString() const
{
return d->stringValue;
return d->data->stringValue;
}
ByteVector ASF::Attribute::toByteVector() const
{
if(d->pictureValue.isValid())
return d->pictureValue.render();
return d->byteVectorValue;
if(d->data->pictureValue.isValid())
return d->data->pictureValue.render();
return d->data->byteVectorValue;
}
unsigned short ASF::Attribute::toBool() const
{
return d->numericValue ? 1 : 0;
return d->data->numericValue ? 1 : 0;
}
unsigned short ASF::Attribute::toUShort() const
{
return static_cast<unsigned short>(d->numericValue);
return static_cast<unsigned short>(d->data->numericValue);
}
unsigned int ASF::Attribute::toUInt() const
{
return static_cast<unsigned int>(d->numericValue);
return static_cast<unsigned int>(d->data->numericValue);
}
unsigned long long ASF::Attribute::toULongLong() const
{
return static_cast<unsigned long long>(d->numericValue);
return static_cast<unsigned long long>(d->data->numericValue);
}
ASF::Picture ASF::Attribute::toPicture() const
{
return d->pictureValue;
return d->data->pictureValue;
}
String ASF::Attribute::parse(ASF::File &f, int kind)
{
unsigned int size, nameLength;
String name;
d->pictureValue = Picture::fromInvalid();
d->data->pictureValue = Picture::fromInvalid();
// extended content descriptor
if(kind == 0) {
nameLength = readWORD(&f);
name = readString(&f, nameLength);
d->type = static_cast<ASF::Attribute::AttributeTypes>(readWORD(&f));
d->data->type = ASF::Attribute::AttributeTypes(readWORD(&f));
size = readWORD(&f);
}
// metadata & metadata library
@@ -179,11 +206,11 @@ String ASF::Attribute::parse(ASF::File &f, int kind)
int temp = readWORD(&f);
// metadata library
if(kind == 2) {
d->language = temp;
d->data->language = temp;
}
d->stream = readWORD(&f);
d->data->stream = readWORD(&f);
nameLength = readWORD(&f);
d->type = static_cast<ASF::Attribute::AttributeTypes>(readWORD(&f));
d->data->type = ASF::Attribute::AttributeTypes(readWORD(&f));
size = readDWORD(&f);
name = readString(&f, nameLength);
}
@@ -192,42 +219,42 @@ String ASF::Attribute::parse(ASF::File &f, int kind)
debug("ASF::Attribute::parse() -- Value larger than 64kB");
}
switch(d->type) {
switch(d->data->type) {
case WordType:
d->numericValue = readWORD(&f);
d->data->numericValue = readWORD(&f);
break;
case BoolType:
if(kind == 0) {
d->numericValue = (readDWORD(&f) != 0);
d->data->numericValue = (readDWORD(&f) != 0);
}
else {
d->numericValue = (readWORD(&f) != 0);
d->data->numericValue = (readWORD(&f) != 0);
}
break;
case DWordType:
d->numericValue = readDWORD(&f);
d->data->numericValue = readDWORD(&f);
break;
case QWordType:
d->numericValue = readQWORD(&f);
d->data->numericValue = readQWORD(&f);
break;
case UnicodeType:
d->stringValue = readString(&f, size);
d->data->stringValue = readString(&f, size);
break;
case BytesType:
case GuidType:
d->byteVectorValue = f.readBlock(size);
d->data->byteVectorValue = f.readBlock(size);
break;
}
if(d->type == BytesType && name == "WM/Picture") {
d->pictureValue.parse(d->byteVectorValue);
if(d->pictureValue.isValid()) {
d->byteVectorValue.clear();
if(d->data->type == BytesType && name == "WM/Picture") {
d->data->pictureValue.parse(d->data->byteVectorValue);
if(d->data->pictureValue.isValid()) {
d->data->byteVectorValue.clear();
}
}
@@ -236,7 +263,7 @@ String ASF::Attribute::parse(ASF::File &f, int kind)
int ASF::Attribute::dataSize() const
{
switch (d->type) {
switch (d->data->type) {
case WordType:
return 2;
case BoolType:
@@ -246,14 +273,12 @@ int ASF::Attribute::dataSize() const
case QWordType:
return 5;
case UnicodeType:
return d->stringValue.size() * 2 + 2;
return static_cast<int>(d->data->stringValue.size() * 2 + 2);
case BytesType:
if(d->pictureValue.isValid()) {
return d->pictureValue.dataSize();
}
return d->byteVectorValue.size();
if(d->data->pictureValue.isValid())
return d->data->pictureValue.dataSize();
case GuidType:
return d->byteVectorValue.size();
return static_cast<int>(d->data->byteVectorValue.size());
}
return 0;
}
@@ -262,58 +287,55 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
{
ByteVector data;
switch (d->type) {
switch (d->data->type) {
case WordType:
data.append(ByteVector::fromShort(toUShort(), false));
data.append(ByteVector::fromUInt16LE(toUShort()));
break;
case BoolType:
if(kind == 0) {
data.append(ByteVector::fromUInt(toBool(), false));
data.append(ByteVector::fromUInt32LE(toBool()));
}
else {
data.append(ByteVector::fromShort(toBool(), false));
data.append(ByteVector::fromUInt16LE(toBool()));
}
break;
case DWordType:
data.append(ByteVector::fromUInt(toUInt(), false));
data.append(ByteVector::fromUInt32LE(toUInt()));
break;
case QWordType:
data.append(ByteVector::fromLongLong(toULongLong(), false));
data.append(ByteVector::fromUInt64LE(toULongLong()));
break;
case UnicodeType:
data.append(renderString(d->stringValue));
data.append(renderString(d->data->stringValue));
break;
case BytesType:
if(d->pictureValue.isValid()) {
data.append(d->pictureValue.render());
if(d->data->pictureValue.isValid()) {
data.append(d->data->pictureValue.render());
break;
}
else {
data.append(d->byteVectorValue);
}
break;
case GuidType:
data.append(d->byteVectorValue);
data.append(d->data->byteVectorValue);
break;
}
if(kind == 0) {
data = renderString(name, true) +
ByteVector::fromShort(static_cast<int>(d->type), false) +
ByteVector::fromShort(data.size(), false) +
ByteVector::fromUInt16LE((int)d->data->type) +
ByteVector::fromUInt16LE(data.size()) +
data;
}
else {
ByteVector nameData = renderString(name);
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
ByteVector::fromShort(d->stream, false) +
ByteVector::fromShort(nameData.size(), false) +
ByteVector::fromShort(static_cast<int>(d->type), false) +
ByteVector::fromUInt(data.size(), false) +
data = ByteVector::fromUInt16LE(kind == 2 ? d->data->language : 0) +
ByteVector::fromUInt16LE(d->data->stream) +
ByteVector::fromUInt16LE(nameData.size()) +
ByteVector::fromUInt16LE((int)d->data->type) +
ByteVector::fromUInt32LE(data.size()) +
nameData +
data;
}
@@ -323,20 +345,20 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
int ASF::Attribute::language() const
{
return d->language;
return d->data->language;
}
void ASF::Attribute::setLanguage(int value)
{
d->language = value;
d->data->language = value;
}
int ASF::Attribute::stream() const
{
return d->stream;
return d->data->stream;
}
void ASF::Attribute::setStream(int value)
{
d->stream = value;
d->data->stream = value;
}

View File

@@ -33,6 +33,7 @@
namespace TagLib
{
namespace ASF
{
class File;
@@ -106,7 +107,7 @@ namespace TagLib
/*!
* Construct an attribute as a copy of \a other.
*/
Attribute(const Attribute &other);
Attribute(const Attribute &item);
/*!
* Copies the contents of \a other into this item.
@@ -116,7 +117,7 @@ namespace TagLib
/*!
* Exchanges the content of the Attribute by the content of \a other.
*/
void swap(Attribute &other) noexcept;
void swap(Attribute &other);
/*!
* Destroys the attribute.
@@ -183,24 +184,20 @@ namespace TagLib
*/
void setStream(int value);
#ifndef DO_NOT_DOCUMENT
/* THIS IS PRIVATE, DON'T TOUCH IT! */
String parse(ASF::File &file, int kind = 0);
#endif
//! Returns the size of the stored data
int dataSize() const;
private:
friend class File;
String parse(ASF::File &file, int kind = 0);
ByteVector render(const String &name, int kind = 0) const;
class AttributePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::shared_ptr<AttributePrivate> d;
AttributePrivate *d;
};
} // namespace ASF
} // namespace TagLib
}
}
#endif

View File

@@ -23,14 +23,14 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tdebug.h>
#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tstring.h>
#include <tagutils.h>
#include <tsmartptr.h>
#include "asffile.h"
#include <utility>
#include "tdebug.h"
#include "tpropertymap.h"
#include "tbytevectorlist.h"
#include "tagutils.h"
#include "asftag.h"
#include "asfproperties.h"
#include "asfutils.h"
@@ -51,28 +51,24 @@ public:
class MetadataObject;
class MetadataLibraryObject;
FilePrivate()
{
objects.setAutoDelete(true);
}
typedef List<SHARED_PTR<BaseObject> > ObjectList;
typedef ObjectList::ConstIterator ObjectConstIterator;
~FilePrivate() = default;
FilePrivate():
headerSize(0) {}
FilePrivate(const FilePrivate &) = delete;
FilePrivate &operator=(const FilePrivate &) = delete;
unsigned long long headerSize;
unsigned long long headerSize { 0 };
SCOPED_PTR<ASF::Tag> tag;
SCOPED_PTR<ASF::AudioProperties> properties;
std::unique_ptr<ASF::Tag> tag;
std::unique_ptr<ASF::Properties> properties;
ObjectList objects;
List<BaseObject *> objects;
ContentDescriptionObject *contentDescriptionObject { nullptr };
ExtendedContentDescriptionObject *extendedContentDescriptionObject { nullptr };
HeaderExtensionObject *headerExtensionObject { nullptr };
MetadataObject *metadataObject { nullptr };
MetadataLibraryObject *metadataLibraryObject { nullptr };
SHARED_PTR<ContentDescriptionObject> contentDescriptionObject;
SHARED_PTR<ExtendedContentDescriptionObject> extendedContentDescriptionObject;
SHARED_PTR<HeaderExtensionObject> headerExtensionObject;
SHARED_PTR<MetadataObject> metadataObject;
SHARED_PTR<MetadataLibraryObject> metadataLibraryObject;
};
namespace
@@ -89,15 +85,15 @@ 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
{
public:
ByteVector data;
virtual ~BaseObject() = default;
virtual ~BaseObject() {}
virtual ByteVector guid() const = 0;
virtual void parse(ASF::File *file, long long size);
virtual void parse(ASF::File *file, unsigned int size);
virtual ByteVector render(ASF::File *file);
};
@@ -105,74 +101,74 @@ class ASF::File::FilePrivate::UnknownObject : public ASF::File::FilePrivate::Bas
{
ByteVector myGuid;
public:
UnknownObject(const ByteVector &guid);
ByteVector guid() const override;
explicit UnknownObject(const ByteVector &guid);
ByteVector guid() const;
};
class ASF::File::FilePrivate::FilePropertiesObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
};
class ASF::File::FilePrivate::StreamPropertiesObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
};
class ASF::File::FilePrivate::ContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector render(ASF::File *file) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
ByteVector render(ASF::File *file);
};
class ASF::File::FilePrivate::ExtendedContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVectorList attributeData;
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector render(ASF::File *file) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
ByteVector render(ASF::File *file);
};
class ASF::File::FilePrivate::MetadataObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVectorList attributeData;
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector render(ASF::File *file) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
ByteVector render(ASF::File *file);
};
class ASF::File::FilePrivate::MetadataLibraryObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVectorList attributeData;
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector render(ASF::File *file) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
ByteVector render(ASF::File *file);
};
class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject
{
public:
List<ASF::File::FilePrivate::BaseObject *> objects;
ObjectList objects;
HeaderExtensionObject();
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector render(ASF::File *file) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
ByteVector render(ASF::File *file);
};
class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid() const override;
void parse(ASF::File *file, long long size) override;
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
private:
enum CodecType
@@ -183,10 +179,10 @@ private:
};
};
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, long long size)
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
{
data.clear();
if(size > 24 && size <= file->length())
if(size > 24 && static_cast<long long>(size) <= file->length())
data = file->readBlock(size - 24);
else
data = ByteVector();
@@ -194,7 +190,7 @@ void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, long long size)
ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/)
{
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
return guid() + ByteVector::fromUInt64LE(data.size() + 24) + data;
}
ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
@@ -211,7 +207,7 @@ ByteVector ASF::File::FilePrivate::FilePropertiesObject::guid() const
return filePropertiesGuid;
}
void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, long long size)
void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size)
{
BaseObject::parse(file, size);
if(data.size() < 64) {
@@ -219,8 +215,8 @@ void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, long l
return;
}
const long long duration = data.toLongLong(40, false);
const long long preroll = data.toLongLong(56, false);
const long long duration = data.toInt64LE(40);
const long long preroll = data.toInt64LE(56);
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
}
@@ -229,7 +225,7 @@ ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const
return streamPropertiesGuid;
}
void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, long long size)
void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size)
{
BaseObject::parse(file, size);
if(data.size() < 70) {
@@ -237,11 +233,11 @@ void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, long
return;
}
file->d->properties->setCodec(data.toUShort(54, false));
file->d->properties->setChannels(data.toUShort(56, false));
file->d->properties->setSampleRate(data.toUInt(58, false));
file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
file->d->properties->setBitsPerSample(data.toUShort(68, false));
file->d->properties->setCodec(data.toUInt16LE(54));
file->d->properties->setChannels(data.toUInt16LE(56));
file->d->properties->setSampleRate(data.toUInt32LE(58));
file->d->properties->setBitrate(static_cast<int>(data.toUInt32LE(62) * 8.0 / 1000.0 + 0.5));
file->d->properties->setBitsPerSample(data.toUInt16LE(68));
}
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
@@ -249,7 +245,7 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
return contentDescriptionGuid;
}
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, long long /*size*/)
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
{
const int titleLength = readWORD(file);
const int artistLength = readWORD(file);
@@ -271,11 +267,11 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *f
const ByteVector v4 = renderString(file->d->tag->comment());
const ByteVector v5 = renderString(file->d->tag->rating());
data.clear();
data.append(ByteVector::fromShort(v1.size(), false));
data.append(ByteVector::fromShort(v2.size(), false));
data.append(ByteVector::fromShort(v3.size(), false));
data.append(ByteVector::fromShort(v4.size(), false));
data.append(ByteVector::fromShort(v5.size(), false));
data.append(ByteVector::fromUInt16LE(v1.size()));
data.append(ByteVector::fromUInt16LE(v2.size()));
data.append(ByteVector::fromUInt16LE(v3.size()));
data.append(ByteVector::fromUInt16LE(v4.size()));
data.append(ByteVector::fromUInt16LE(v5.size()));
data.append(v1);
data.append(v2);
data.append(v3);
@@ -289,7 +285,7 @@ ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() cons
return extendedContentDescriptionGuid;
}
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, long long /*size*/)
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
{
int count = readWORD(file);
while(count--) {
@@ -302,7 +298,7 @@ void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(ByteVector::fromUInt16LE(attributeData.size()));
data.append(attributeData.toByteVector(""));
return BaseObject::render(file);
}
@@ -312,7 +308,7 @@ ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
return metadataGuid;
}
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, long long /*size*/)
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/)
{
int count = readWORD(file);
while(count--) {
@@ -325,7 +321,7 @@ void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, long long /*
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(ByteVector::fromUInt16LE(attributeData.size()));
data.append(attributeData.toByteVector(""));
return BaseObject::render(file);
}
@@ -335,7 +331,7 @@ ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
return metadataLibraryGuid;
}
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, long long /*size*/)
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/)
{
int count = readWORD(file);
while(count--) {
@@ -348,14 +344,13 @@ void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, long
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(ByteVector::fromUInt16LE(attributeData.size()));
data.append(attributeData.toByteVector(""));
return BaseObject::render(file);
}
ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject()
{
objects.setAutoDelete(true);
}
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
@@ -363,36 +358,36 @@ ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
return headerExtensionGuid;
}
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, long long /*size*/)
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->seek(18, File::Current);
long long dataSize = readDWORD(file);
long long dataPos = 0;
while(dataPos < dataSize) {
ByteVector uid = file->readBlock(16);
if(uid.size() != 16) {
ByteVector guid = file->readBlock(16);
if(guid.size() != 16) {
file->setValid(false);
break;
}
bool ok;
long long size = readQWORD(file, &ok);
if(!ok || size < 0 || size > dataSize - dataPos) {
if(!ok) {
file->setValid(false);
break;
}
BaseObject *obj;
if(uid == metadataGuid) {
file->d->metadataObject = new MetadataObject();
SHARED_PTR<BaseObject> obj;
if(guid == metadataGuid) {
file->d->metadataObject.reset(new MetadataObject());
obj = file->d->metadataObject;
}
else if(uid == metadataLibraryGuid) {
file->d->metadataLibraryObject = new MetadataLibraryObject();
else if(guid == metadataLibraryGuid) {
file->d->metadataLibraryObject.reset(new MetadataLibraryObject());
obj = file->d->metadataLibraryObject;
}
else {
obj = new UnknownObject(uid);
obj.reset(new UnknownObject(guid));
}
obj->parse(file, size);
obj->parse(file, (unsigned int)size);
objects.append(obj);
dataPos += size;
}
@@ -401,10 +396,10 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, long
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file)
{
data.clear();
for(const auto &object : std::as_const(objects)) {
data.append(object->render(file));
for(ObjectConstIterator it = objects.begin(); it != objects.end(); ++it) {
data.append((*it)->render(file));
}
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt32LE(data.size()) + data;
return BaseObject::render(file);
}
@@ -413,7 +408,7 @@ ByteVector ASF::File::FilePrivate::CodecListObject::guid() const
return codecListGuid;
}
void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, long long size)
void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size)
{
BaseObject::parse(file, size);
if(data.size() <= 20) {
@@ -423,7 +418,7 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, long long s
unsigned int pos = 16;
const int count = data.toUInt(pos, false);
const int count = data.toUInt32LE(pos);
pos += 4;
for(int i = 0; i < count; ++i) {
@@ -431,22 +426,22 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, long long s
if(pos >= data.size())
break;
const auto type = static_cast<CodecType>(data.toUShort(pos, false));
const CodecType type = static_cast<CodecType>(data.toUInt16LE(pos));
pos += 2;
int nameLength = data.toUShort(pos, false);
int nameLength = data.toUInt16LE(pos);
pos += 2;
const unsigned int namePos = pos;
pos += nameLength * 2;
const int descLength = data.toUShort(pos, false);
const int descLength = data.toUInt16LE(pos);
pos += 2;
const unsigned int descPos = pos;
pos += descLength * 2;
const int infoLength = data.toUShort(pos, false);
const int infoLength = data.toUInt16LE(pos);
pos += 2 + infoLength * 2;
if(type == CodecListObject::Audio) {
@@ -479,45 +474,33 @@ bool ASF::File::isSupported(IOStream *stream)
// public members
////////////////////////////////////////////////////////////////////////////////
ASF::File::File(FileName file, bool, Properties::ReadStyle) :
ASF::File::File(FileName file, bool, AudioProperties::ReadStyle) :
TagLib::File(file),
d(std::make_unique<FilePrivate>())
d(new FilePrivate())
{
if(isOpen())
read();
}
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) :
ASF::File::File(IOStream *stream, bool, AudioProperties::ReadStyle) :
TagLib::File(stream),
d(std::make_unique<FilePrivate>())
d(new FilePrivate())
{
if(isOpen())
read();
}
ASF::File::~File() = default;
ASF::File::~File()
{
delete d;
}
ASF::Tag *ASF::File::tag() const
{
return d->tag.get();
}
PropertyMap ASF::File::properties() const
{
return d->tag->properties();
}
void ASF::File::removeUnsupportedProperties(const StringList &properties)
{
d->tag->removeUnsupportedProperties(properties);
}
PropertyMap ASF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
ASF::Properties *ASF::File::audioProperties() const
ASF::AudioProperties *ASF::File::audioProperties() const
{
return d->properties.get();
}
@@ -535,23 +518,23 @@ bool ASF::File::save()
}
if(!d->contentDescriptionObject) {
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
d->contentDescriptionObject.reset(new FilePrivate::ContentDescriptionObject());
d->objects.append(d->contentDescriptionObject);
}
if(!d->extendedContentDescriptionObject) {
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
d->extendedContentDescriptionObject.reset(new FilePrivate::ExtendedContentDescriptionObject());
d->objects.append(d->extendedContentDescriptionObject);
}
if(!d->headerExtensionObject) {
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
d->headerExtensionObject.reset(new FilePrivate::HeaderExtensionObject());
d->objects.append(d->headerExtensionObject);
}
if(!d->metadataObject) {
d->metadataObject = new FilePrivate::MetadataObject();
d->metadataObject.reset(new FilePrivate::MetadataObject());
d->headerExtensionObject->objects.append(d->metadataObject);
}
if(!d->metadataLibraryObject) {
d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject();
d->metadataLibraryObject.reset(new FilePrivate::MetadataLibraryObject());
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
}
@@ -559,11 +542,19 @@ bool ASF::File::save()
d->metadataObject->attributeData.clear();
d->metadataLibraryObject->attributeData.clear();
for(const auto &[name, attributes] : std::as_const(d->tag->attributeListMap())) {
const AttributeListMap allAttributes = d->tag->attributeListMap();
for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) {
const String &name = it->first;
const AttributeList &attributes = it->second;
bool inExtendedContentDescriptionObject = false;
bool inMetadataObject = false;
for(const auto &attribute : attributes) {
for(AttributeList::ConstIterator jt = attributes.begin(); jt != attributes.end(); ++jt) {
const Attribute &attribute = *jt;
const bool largeValue = (attribute.dataSize() > 65535);
const bool guid = (attribute.type() == Attribute::GuidType);
@@ -582,16 +573,16 @@ bool ASF::File::save()
}
ByteVector data;
for(const auto &object : std::as_const(d->objects)) {
data.append(object->render(this));
for(FilePrivate::ObjectConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) {
data.append((*it)->render(this));
}
seek(16);
writeBlock(ByteVector::fromLongLong(data.size() + 30, false));
writeBlock(ByteVector::fromUInt(d->objects.size(), false));
writeBlock(ByteVector::fromUInt64LE(data.size() + 30));
writeBlock(ByteVector::fromUInt32LE(d->objects.size()));
writeBlock(ByteVector("\x01\x02", 2));
insert(data, 30, static_cast<unsigned long>(d->headerSize - 30));
insert(data, 30, static_cast<size_t>(d->headerSize - 30));
d->headerSize = data.size() + 30;
@@ -613,8 +604,8 @@ void ASF::File::read()
return;
}
d->tag = std::make_unique<ASF::Tag>();
d->properties = std::make_unique<ASF::Properties>();
d->tag.reset(new ASF::Tag());
d->properties.reset(new ASF::AudioProperties());
bool ok;
d->headerSize = readQWORD(this, &ok);
@@ -629,42 +620,42 @@ void ASF::File::read()
}
seek(2, Current);
FilePrivate::FilePropertiesObject *filePropertiesObject = nullptr;
FilePrivate::StreamPropertiesObject *streamPropertiesObject = nullptr;
SHARED_PTR<FilePrivate::FilePropertiesObject> filePropertiesObject;
SHARED_PTR<FilePrivate::StreamPropertiesObject> streamPropertiesObject;
for(int i = 0; i < numObjects; i++) {
const ByteVector guid = readBlock(16);
if(guid.size() != 16) {
setValid(false);
break;
}
auto size = readQWORD(this, &ok);
long size = (long)readQWORD(this, &ok);
if(!ok) {
setValid(false);
break;
}
FilePrivate::BaseObject *obj;
SHARED_PTR<FilePrivate::BaseObject> obj;
if(guid == filePropertiesGuid) {
filePropertiesObject = new FilePrivate::FilePropertiesObject();
filePropertiesObject.reset(new FilePrivate::FilePropertiesObject());
obj = filePropertiesObject;
}
else if(guid == streamPropertiesGuid) {
streamPropertiesObject = new FilePrivate::StreamPropertiesObject();
streamPropertiesObject.reset(new FilePrivate::StreamPropertiesObject());
obj = streamPropertiesObject;
}
else if(guid == contentDescriptionGuid) {
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
d->contentDescriptionObject.reset(new FilePrivate::ContentDescriptionObject());
obj = d->contentDescriptionObject;
}
else if(guid == extendedContentDescriptionGuid) {
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
d->extendedContentDescriptionObject.reset(new FilePrivate::ExtendedContentDescriptionObject());
obj = d->extendedContentDescriptionObject;
}
else if(guid == headerExtensionGuid) {
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
d->headerExtensionObject.reset(new FilePrivate::HeaderExtensionObject());
obj = d->headerExtensionObject;
}
else if(guid == codecListGuid) {
obj = new FilePrivate::CodecListObject();
obj.reset(new FilePrivate::CodecListObject());
}
else {
if(guid == contentEncryptionGuid ||
@@ -672,7 +663,7 @@ void ASF::File::read()
guid == advancedContentEncryptionGuid) {
d->properties->setEncrypted(true);
}
obj = new FilePrivate::UnknownObject(guid);
obj.reset(new FilePrivate::UnknownObject(guid));
}
obj->parse(this, size);
d->objects.append(obj);

View File

@@ -26,15 +26,17 @@
#ifndef TAGLIB_ASFFILE_H
#define TAGLIB_ASFFILE_H
#include "tag.h"
#include "tfile.h"
#include "taglib_export.h"
#include "tag.h"
#include "asfproperties.h"
#include "asftag.h"
namespace TagLib {
//! An implementation of ASF (WMA) metadata
namespace ASF {
/*!
* This implements and provides an interface for ASF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
@@ -46,17 +48,21 @@ namespace TagLib {
public:
/*!
* Constructs an ASF file from \a file.
* Contructs an ASF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
* read.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Constructs an ASF file from \a stream.
* Contructs an ASF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
@@ -66,15 +72,12 @@ namespace TagLib {
* responsible for deleting it after the File object.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Destroys this instance of the File.
*/
~File() override;
File(const File &) = delete;
File &operator=(const File &) = delete;
virtual ~File();
/*!
* Returns a pointer to the ASF tag of the file.
@@ -86,35 +89,19 @@ namespace TagLib {
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*/
Tag *tag() const override;
/*!
* Implements the unified property interface -- export function.
*/
PropertyMap properties() const override;
/*!
* Removes unsupported properties. Forwards to the actual Tag's
* removeUnsupportedProperties() function.
*/
void removeUnsupportedProperties(const StringList &properties) override;
/*!
* Implements the unified property interface -- import function.
*/
PropertyMap setProperties(const PropertyMap &) override;
virtual Tag *tag() const;
/*!
* Returns the ASF audio properties for this file.
*/
Properties *audioProperties() const override;
virtual AudioProperties *audioProperties() const;
/*!
* Save the file.
*
* This returns true if the save was successful.
*/
bool save() override;
virtual bool save();
/*!
* Returns whether or not the given \a stream can be opened as an ASF
@@ -129,10 +116,11 @@ namespace TagLib {
void read();
class FilePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FilePrivate> d;
FilePrivate *d;
};
} // namespace ASF
} // namespace TagLib
}
}
#endif

View File

@@ -23,21 +23,36 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "asfpicture.h"
#include <taglib.h>
#include <tdebug.h>
#include <tsmartptr.h>
#include "asfattribute.h"
#include "asffile.h"
#include "asfpicture.h"
#include "asfutils.h"
using namespace TagLib;
namespace
{
struct PictureData
{
bool valid;
ASF::Picture::Type type;
String mimeType;
String description;
ByteVector picture;
};
}
class ASF::Picture::PicturePrivate
{
public:
bool valid;
Type type;
String mimeType;
String description;
ByteVector picture;
PicturePrivate() :
data(new PictureData()) {}
SHARED_PTR<PictureData> data;
};
////////////////////////////////////////////////////////////////////////////////
@@ -45,69 +60,80 @@ public:
////////////////////////////////////////////////////////////////////////////////
ASF::Picture::Picture() :
d(std::make_shared<PicturePrivate>())
d(new PicturePrivate())
{
d->valid = true;
d->data->valid = true;
}
ASF::Picture::Picture(const Picture &) = default;
ASF::Picture::~Picture() = default;
ASF::Picture::Picture(const Picture& other) :
d(new PicturePrivate(*other.d))
{
}
ASF::Picture::~Picture()
{
delete d;
}
bool ASF::Picture::isValid() const
{
return d->valid;
return d->data->valid;
}
String ASF::Picture::mimeType() const
{
return d->mimeType;
return d->data->mimeType;
}
void ASF::Picture::setMimeType(const String &value)
{
d->mimeType = value;
d->data->mimeType = value;
}
ASF::Picture::Type ASF::Picture::type() const
{
return d->type;
return d->data->type;
}
void ASF::Picture::setType(const ASF::Picture::Type& t)
{
d->type = t;
d->data->type = t;
}
String ASF::Picture::description() const
{
return d->description;
return d->data->description;
}
void ASF::Picture::setDescription(const String &desc)
{
d->description = desc;
d->data->description = desc;
}
ByteVector ASF::Picture::picture() const
{
return d->picture;
return d->data->picture;
}
void ASF::Picture::setPicture(const ByteVector &p)
{
d->picture = p;
d->data->picture = p;
}
int ASF::Picture::dataSize() const
{
return
9 + (d->mimeType.length() + d->description.length()) * 2 +
d->picture.size();
return static_cast<int>(
9 + (d->data->mimeType.length() + d->data->description.length()) * 2 +
d->data->picture.size());
}
ASF::Picture &ASF::Picture::operator=(const ASF::Picture &) = default;
ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other)
{
Picture(other).swap(*this);
return *this;
}
void ASF::Picture::swap(Picture &other) noexcept
void ASF::Picture::swap(Picture &other)
{
using std::swap;
@@ -120,46 +146,47 @@ ByteVector ASF::Picture::render() const
return ByteVector();
return
ByteVector(static_cast<char>(d->type)) +
ByteVector::fromUInt(d->picture.size(), false) +
renderString(d->mimeType) +
renderString(d->description) +
d->picture;
ByteVector((char)d->data->type) +
ByteVector::fromUInt32LE(d->data->picture.size()) +
renderString(d->data->mimeType) +
renderString(d->data->description) +
d->data->picture;
}
void ASF::Picture::parse(const ByteVector& bytes)
{
d->valid = false;
d->data->valid = false;
if(bytes.size() < 9)
return;
int pos = 0;
d->type = static_cast<Type>(bytes[0]); ++pos;
const unsigned int dataLen = bytes.toUInt(pos, false); pos+=4;
size_t pos = 0;
d->data->type = (Type)bytes[0]; ++pos;
const unsigned int dataLen = bytes.toUInt32LE(pos); pos+=4;
const ByteVector nullStringTerminator(2, 0);
int endPos = bytes.find(nullStringTerminator, pos, 2);
if(endPos < 0)
size_t endPos = bytes.find(nullStringTerminator, pos, 2);
if(endPos == ByteVector::npos())
return;
d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
d->data->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
pos = endPos+2;
endPos = bytes.find(nullStringTerminator, pos, 2);
if(endPos < 0)
if(endPos == ByteVector::npos())
return;
d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
d->data->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
pos = endPos+2;
if(dataLen + pos != bytes.size())
return;
d->picture = bytes.mid(pos, dataLen);
d->valid = true;
d->data->picture = bytes.mid(pos, dataLen);
d->data->valid = true;
return;
}
ASF::Picture ASF::Picture::fromInvalid()
{
Picture ret;
ret.d->valid = false;
ret.d->data->valid = false;
return ret;
}

View File

@@ -28,7 +28,6 @@
#include "tstring.h"
#include "tbytevector.h"
#include "tpicturetype.h"
#include "taglib_export.h"
#include "attachedpictureframe.h"
@@ -36,6 +35,7 @@ namespace TagLib
{
namespace ASF
{
class Attribute;
//! An ASF attached picture interface implementation
@@ -47,13 +47,57 @@ namespace TagLib
* \see Attribute::toPicture()
* \see Attribute::Attribute(const Picture& picture)
*/
class TAGLIB_EXPORT Picture {
class TAGLIB_EXPORT Picture
{
public:
/*!
* This describes the function or content of the picture.
*/
DECLARE_PICTURE_TYPE_ENUM(Type)
enum Type {
//! A type not enumerated below
Other = 0x00,
//! 32x32 PNG image that should be used as the file icon
FileIcon = 0x01,
//! File icon of a different size or format
OtherFileIcon = 0x02,
//! Front cover image of the album
FrontCover = 0x03,
//! Back cover image of the album
BackCover = 0x04,
//! Inside leaflet page of the album
LeafletPage = 0x05,
//! Image from the album itself
Media = 0x06,
//! Picture of the lead artist or soloist
LeadArtist = 0x07,
//! Picture of the artist or performer
Artist = 0x08,
//! Picture of the conductor
Conductor = 0x09,
//! Picture of the band or orchestra
Band = 0x0A,
//! Picture of the composer
Composer = 0x0B,
//! Picture of the lyricist or text writer
Lyricist = 0x0C,
//! Picture of the recording location or studio
RecordingLocation = 0x0D,
//! Picture of the artists during recording
DuringRecording = 0x0E,
//! Picture of the artists during performance
DuringPerformance = 0x0F,
//! Picture from a movie or video related to the track
MovieScreenCapture = 0x10,
//! Picture of a large, coloured fish
ColouredFish = 0x11,
//! Illustration related to the track
Illustration = 0x12,
//! Logo of the band or performer
BandLogo = 0x13,
//! Logo of the publisher (record company)
PublisherLogo = 0x14
};
/*!
* Constructs an empty picture.
@@ -61,7 +105,7 @@ namespace TagLib
Picture();
/*!
* Construct an picture as a copy of \a other.
* Constructs an picture as a copy of \a other.
*/
Picture(const Picture& other);
@@ -78,7 +122,7 @@ namespace TagLib
/*!
* Exchanges the content of the Picture by the content of \a other.
*/
void swap(Picture &other) noexcept;
void swap(Picture &other);
/*!
* Returns true if Picture stores valid picture
@@ -164,18 +208,16 @@ namespace TagLib
*/
int dataSize() const;
#ifndef DO_NOT_DOCUMENT
/* THIS IS PRIVATE, DON'T TOUCH IT! */
void parse(const ByteVector& );
static Picture fromInvalid();
#endif
private:
friend class Attribute;
private:
class PicturePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::shared_ptr<PicturePrivate> d;
};
} // namespace ASF
} // namespace TagLib
void parse(const ByteVector &);
static Picture fromInvalid();
class PicturePrivate;
PicturePrivate *d;
};
}
}
#endif // ASFPICTURE_H

View File

@@ -23,77 +23,101 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tdebug.h>
#include <tstring.h>
#include "asfproperties.h"
using namespace TagLib;
class ASF::Properties::PropertiesPrivate
class ASF::AudioProperties::PropertiesPrivate
{
public:
int length { 0 };
int bitrate { 0 };
int sampleRate { 0 };
int channels { 0 };
int bitsPerSample { 0 };
ASF::Properties::Codec codec { ASF::Properties::Unknown };
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
bitsPerSample(0),
codec(ASF::AudioProperties::Unknown),
encrypted(false) {}
int length;
int bitrate;
int sampleRate;
int channels;
int bitsPerSample;
ASF::AudioProperties::Codec codec;
String codecName;
String codecDescription;
bool encrypted { false };
bool encrypted;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
ASF::Properties::Properties() :
AudioProperties(AudioProperties::Average),
d(std::make_unique<PropertiesPrivate>())
ASF::AudioProperties::AudioProperties() :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
}
ASF::Properties::~Properties() = default;
ASF::AudioProperties::~AudioProperties()
{
delete d;
}
int ASF::Properties::lengthInMilliseconds() const
int ASF::AudioProperties::length() const
{
return lengthInSeconds();
}
int ASF::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int ASF::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int ASF::Properties::bitrate() const
int ASF::AudioProperties::bitrate() const
{
return d->bitrate;
}
int ASF::Properties::sampleRate() const
int ASF::AudioProperties::sampleRate() const
{
return d->sampleRate;
}
int ASF::Properties::channels() const
int ASF::AudioProperties::channels() const
{
return d->channels;
}
int ASF::Properties::bitsPerSample() const
int ASF::AudioProperties::bitsPerSample() const
{
return d->bitsPerSample;
}
ASF::Properties::Codec ASF::Properties::codec() const
ASF::AudioProperties::Codec ASF::AudioProperties::codec() const
{
return d->codec;
}
String ASF::Properties::codecName() const
String ASF::AudioProperties::codecName() const
{
return d->codecName;
}
String ASF::Properties::codecDescription() const
String ASF::AudioProperties::codecDescription() const
{
return d->codecDescription;
}
bool ASF::Properties::isEncrypted() const
bool ASF::AudioProperties::isEncrypted() const
{
return d->encrypted;
}
@@ -102,32 +126,32 @@ bool ASF::Properties::isEncrypted() const
// private members
////////////////////////////////////////////////////////////////////////////////
void ASF::Properties::setLengthInMilliseconds(int value)
void ASF::AudioProperties::setLengthInMilliseconds(int value)
{
d->length = value;
}
void ASF::Properties::setBitrate(int value)
void ASF::AudioProperties::setBitrate(int value)
{
d->bitrate = value;
}
void ASF::Properties::setSampleRate(int value)
void ASF::AudioProperties::setSampleRate(int value)
{
d->sampleRate = value;
}
void ASF::Properties::setChannels(int value)
void ASF::AudioProperties::setChannels(int value)
{
d->channels = value;
}
void ASF::Properties::setBitsPerSample(int value)
void ASF::AudioProperties::setBitsPerSample(int value)
{
d->bitsPerSample = value;
}
void ASF::Properties::setCodec(int value)
void ASF::AudioProperties::setCodec(int value)
{
switch(value)
{
@@ -149,17 +173,17 @@ void ASF::Properties::setCodec(int value)
}
}
void ASF::Properties::setCodecName(const String &value)
void ASF::AudioProperties::setCodecName(const String &value)
{
d->codecName = value;
}
void ASF::Properties::setCodecDescription(const String &value)
void ASF::AudioProperties::setCodecDescription(const String &value)
{
d->codecDescription = value;
}
void ASF::Properties::setEncrypted(bool value)
void ASF::AudioProperties::setEncrypted(bool value)
{
d->encrypted = value;
}

View File

@@ -26,17 +26,22 @@
#ifndef TAGLIB_ASFPROPERTIES_H
#define TAGLIB_ASFPROPERTIES_H
#include "audioproperties.h"
#include "tstring.h"
#include "taglib_export.h"
#include "audioproperties.h"
namespace TagLib {
namespace ASF {
//! An implementation of ASF audio properties
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
namespace ASF {
class File;
//! An implementation of ASF audio properties
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
friend class File;
public:
/*!
* Audio codec types can be used in ASF file.
*/
@@ -69,39 +74,54 @@ namespace TagLib {
};
/*!
* Creates an instance of ASF::Properties.
* Creates an instance of ASF::AudioProperties.
*/
Properties();
AudioProperties();
/*!
* Destroys this ASF::Properties instance.
* Destroys this ASF::AudioProperties instance.
*/
~Properties() override;
virtual ~AudioProperties();
Properties(const Properties &) = delete;
Properties &operator=(const Properties &) = delete;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
virtual int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
int lengthInMilliseconds() const override;
virtual int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
int bitrate() const override;
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
int sampleRate() const override;
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
int channels() const override;
virtual int channels() const;
/*!
* Returns the number of bits per audio sample.
@@ -140,7 +160,7 @@ namespace TagLib {
*/
bool isEncrypted() const;
#ifndef DO_NOT_DOCUMENT
private:
void setLengthInMilliseconds(int value);
void setBitrate(int value);
void setSampleRate(int value);
@@ -150,13 +170,13 @@ namespace TagLib {
void setCodecName(const String &value);
void setCodecDescription(const String &value);
void setEncrypted(bool value);
#endif
private:
class PropertiesPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<PropertiesPrivate> d;
PropertiesPrivate *d;
};
} // namespace ASF
} // namespace TagLib
}
}
#endif

View File

@@ -23,29 +23,12 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tpicturemap.h>
#include <tpropertymap.h>
#include "asftag.h"
#include <array>
#include <utility>
#include "tpropertymap.h"
#include "asfattribute.h"
#include "asfpicture.h"
using namespace TagLib;
namespace
{
StringList attributeListToStringList(const ASF::AttributeList &attributes)
{
StringList strs;
for(const auto &attribute : attributes) {
strs.append(attribute.toString());
}
return strs;
}
} // namespace
class ASF::Tag::TagPrivate
{
public:
@@ -58,11 +41,15 @@ public:
};
ASF::Tag::Tag() :
d(std::make_unique<TagPrivate>())
TagLib::Tag(),
d(new TagPrivate())
{
}
ASF::Tag::~Tag() = default;
ASF::Tag::~Tag()
{
delete d;
}
String ASF::Tag::title() const
{
@@ -77,8 +64,7 @@ String ASF::Tag::artist() const
String ASF::Tag::album() const
{
if(d->attributeListMap.contains("WM/AlbumTitle"))
return joinTagValues(
attributeListToStringList(d->attributeListMap.value("WM/AlbumTitle")));
return d->attributeListMap["WM/AlbumTitle"][0].toString();
return String();
}
@@ -110,7 +96,8 @@ unsigned int ASF::Tag::track() const
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
if(attr.type() == ASF::Attribute::DWordType)
return attr.toUInt();
return attr.toString().toInt();
else
return attr.toString().toInt();
}
if(d->attributeListMap.contains("WM/Track"))
return d->attributeListMap["WM/Track"][0].toUInt();
@@ -120,11 +107,95 @@ unsigned int ASF::Tag::track() const
String ASF::Tag::genre() const
{
if(d->attributeListMap.contains("WM/Genre"))
return joinTagValues(
attributeListToStringList(d->attributeListMap.value("WM/Genre")));
return d->attributeListMap["WM/Genre"][0].toString();
return String();
}
PictureMap ASF::Tag::pictures() const
{
PictureMap map;
if(d->attributeListMap.contains("WM/Picture")) {
AttributeList list = d->attributeListMap["WM/Picture"];
for(AttributeList::ConstIterator it = list.begin();
it != list.end();
++it) {
ASF::Picture asfPicture = (*it).toPicture();
TagLib::Picture::Type type;
switch(asfPicture.type()) {
case ASF::Picture::FileIcon:
type = TagLib::Picture::FileIcon;
break;
case ASF::Picture::OtherFileIcon:
type = TagLib::Picture::OtherFileIcon;
break;
case ASF::Picture::FrontCover:
type = TagLib::Picture::FrontCover;
break;
case ASF::Picture::BackCover:
type = TagLib::Picture::BackCover;
break;
case ASF::Picture::LeafletPage:
type = TagLib::Picture::LeafletPage;
break;
case ASF::Picture::Media:
type = TagLib::Picture::Media;
break;
case ASF::Picture::LeadArtist:
type = TagLib::Picture::LeadArtist;
break;
case ASF::Picture::Artist:
type = TagLib::Picture::Artist;
break;
case ASF::Picture::Conductor:
type = TagLib::Picture::Conductor;
break;
case ASF::Picture::Band:
type = TagLib::Picture::Band;
break;
case ASF::Picture::Composer:
type = TagLib::Picture::Composer;
break;
case ASF::Picture::Lyricist:
type = TagLib::Picture::Lyricist;
break;
case ASF::Picture::RecordingLocation:
type = TagLib::Picture::RecordingLocation;
break;
case ASF::Picture::DuringRecording:
type = TagLib::Picture::DuringRecording;
break;
case ASF::Picture::DuringPerformance:
type = TagLib::Picture::DuringPerformance;
break;
case ASF::Picture::MovieScreenCapture:
type = TagLib::Picture::MovieScreenCapture;
break;
case ASF::Picture::ColouredFish:
type = TagLib::Picture::ColouredFish;
break;
case ASF::Picture::Illustration:
type = TagLib::Picture::Illustration;
break;
case ASF::Picture::BandLogo:
type = TagLib::Picture::BandLogo;
break;
case ASF::Picture::PublisherLogo:
type = TagLib::Picture::PublisherLogo;
break;
default:
type = TagLib::Picture::Other;
break;
}
TagLib::Picture picture(asfPicture.picture(),
type,
asfPicture.mimeType(),
asfPicture.description());
map.insert(picture);
}
}
return PictureMap(map);
}
void ASF::Tag::setTitle(const String &value)
{
d->title = value;
@@ -170,6 +241,94 @@ void ASF::Tag::setTrack(unsigned int value)
setAttribute("WM/TrackNumber", String::number(value));
}
void ASF::Tag::setPictures(const PictureMap &l)
{
removeItem("WM/Picture");
for(PictureMap::ConstIterator pictureMapIt = l.begin();
pictureMapIt != l.end();
++pictureMapIt)
{
PictureList list = pictureMapIt->second;
for( PictureList::ConstIterator pictureListIt = list.begin();
pictureListIt != list.end();
++pictureListIt)
{
const TagLib::Picture picture = (*pictureListIt);
ASF::Picture asfPicture;
asfPicture.setPicture(picture.data());
asfPicture.setMimeType(picture.mime());
asfPicture.setDescription(picture.description());
switch (picture.type()) {
case TagLib::Picture::Other:
asfPicture.setType(ASF::Picture::Other);
break;
case TagLib::Picture::FileIcon:
asfPicture.setType(ASF::Picture::FileIcon);
break;
case TagLib::Picture::OtherFileIcon:
asfPicture.setType(ASF::Picture::OtherFileIcon);
break;
case TagLib::Picture::FrontCover:
asfPicture.setType(ASF::Picture::FrontCover);
break;
case TagLib::Picture::BackCover:
asfPicture.setType(ASF::Picture::BackCover);
break;
case TagLib::Picture::LeafletPage:
asfPicture.setType(ASF::Picture::LeafletPage);
break;
case TagLib::Picture::Media:
asfPicture.setType(ASF::Picture::Media);
break;
case TagLib::Picture::LeadArtist:
asfPicture.setType(ASF::Picture::LeadArtist);
break;
case TagLib::Picture::Artist:
asfPicture.setType(ASF::Picture::Artist);
break;
case TagLib::Picture::Conductor:
asfPicture.setType(ASF::Picture::Conductor);
break;
case TagLib::Picture::Band:
asfPicture.setType(ASF::Picture::Band);
break;
case TagLib::Picture::Composer:
asfPicture.setType(ASF::Picture::Composer);
break;
case TagLib::Picture::Lyricist:
asfPicture.setType(ASF::Picture::Lyricist);
break;
case TagLib::Picture::RecordingLocation:
asfPicture.setType(ASF::Picture::RecordingLocation);
break;
case TagLib::Picture::DuringRecording:
asfPicture.setType(ASF::Picture::DuringRecording);
break;
case TagLib::Picture::DuringPerformance:
asfPicture.setType(ASF::Picture::DuringPerformance);
break;
case TagLib::Picture::MovieScreenCapture:
asfPicture.setType(ASF::Picture::MovieScreenCapture);
break;
case TagLib::Picture::ColouredFish:
asfPicture.setType(ASF::Picture::ColouredFish);
break;
case TagLib::Picture::Illustration:
asfPicture.setType(ASF::Picture::Illustration);
break;
case TagLib::Picture::BandLogo:
asfPicture.setType(ASF::Picture::BandLogo);
break;
case TagLib::Picture::PublisherLogo:
asfPicture.setType(ASF::Picture::PublisherLogo);
break;
}
addAttribute("WM/Picture", Attribute(asfPicture));
}
}
}
ASF::AttributeListMap& ASF::Tag::attributeListMap()
{
return d->attributeListMap;
@@ -197,9 +356,9 @@ ASF::AttributeList ASF::Tag::attribute(const String &name) const
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
{
AttributeList val;
val.append(attribute);
d->attributeListMap.insert(name, val);
AttributeList value;
value.append(attribute);
d->attributeListMap.insert(name, value);
}
void ASF::Tag::setAttribute(const String &name, const AttributeList &values)
@@ -227,73 +386,59 @@ bool ASF::Tag::isEmpty() const
namespace
{
constexpr std::array keyTranslation {
std::pair("WM/AlbumTitle", "ALBUM"),
std::pair("WM/AlbumArtist", "ALBUMARTIST"),
std::pair("WM/AuthorURL", "ARTISTWEBPAGE"),
std::pair("WM/Composer", "COMPOSER"),
std::pair("WM/Writer", "LYRICIST"),
std::pair("WM/Conductor", "CONDUCTOR"),
std::pair("WM/ModifiedBy", "REMIXER"),
std::pair("WM/Year", "DATE"),
std::pair("WM/OriginalAlbumTitle", "ORIGINALALBUM"),
std::pair("WM/OriginalArtist", "ORIGINALARTIST"),
std::pair("WM/OriginalFilename", "ORIGINALFILENAME"),
std::pair("WM/OriginalLyricist", "ORIGINALLYRICIST"),
std::pair("WM/OriginalReleaseYear", "ORIGINALDATE"),
std::pair("WM/Producer", "PRODUCER"),
std::pair("WM/ContentGroupDescription", "WORK"),
std::pair("WM/SubTitle", "SUBTITLE"),
std::pair("WM/SetSubTitle", "DISCSUBTITLE"),
std::pair("WM/TrackNumber", "TRACKNUMBER"),
std::pair("WM/PartOfSet", "DISCNUMBER"),
std::pair("WM/Genre", "GENRE"),
std::pair("WM/BeatsPerMinute", "BPM"),
std::pair("WM/Mood", "MOOD"),
std::pair("WM/InitialKey", "INITIALKEY"),
std::pair("WM/ISRC", "ISRC"),
std::pair("WM/Lyrics", "LYRICS"),
std::pair("WM/Media", "MEDIA"),
std::pair("WM/Publisher", "LABEL"),
std::pair("WM/CatalogNo", "CATALOGNUMBER"),
std::pair("WM/Barcode", "BARCODE"),
std::pair("WM/EncodedBy", "ENCODEDBY"),
std::pair("WM/EncodingSettings", "ENCODING"),
std::pair("WM/EncodingTime", "ENCODINGTIME"),
std::pair("WM/AudioFileURL", "FILEWEBPAGE"),
std::pair("WM/AlbumSortOrder", "ALBUMSORT"),
std::pair("WM/AlbumArtistSortOrder", "ALBUMARTISTSORT"),
std::pair("WM/ArtistSortOrder", "ARTISTSORT"),
std::pair("WM/TitleSortOrder", "TITLESORT"),
std::pair("WM/Script", "SCRIPT"),
std::pair("WM/Language", "LANGUAGE"),
std::pair("WM/ARTISTS", "ARTISTS"),
std::pair("ASIN", "ASIN"),
std::pair("MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID"),
std::pair("MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID"),
std::pair("MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID"),
std::pair("MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID"),
std::pair("MusicBrainz/Album Release Country", "RELEASECOUNTRY"),
std::pair("MusicBrainz/Album Status", "RELEASESTATUS"),
std::pair("MusicBrainz/Album Type", "RELEASETYPE"),
std::pair("MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID"),
std::pair("MusicBrainz/Release Track Id", "MUSICBRAINZ_RELEASETRACKID"),
std::pair("MusicBrainz/Work Id", "MUSICBRAINZ_WORKID"),
std::pair("MusicIP/PUID", "MUSICIP_PUID"),
std::pair("Acoustid/Id", "ACOUSTID_ID"),
std::pair("Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT"),
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 size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
String translateKey(const String &key)
{
for(const auto &[k, t] : keyTranslation) {
if(key == k)
return t;
for(size_t i = 0; i < keyTranslationSize; ++i) {
if(key == keyTranslation[i][0])
return keyTranslation[i][1];
}
return String();
}
} // namespace
}
PropertyMap ASF::Tag::properties() const
{
@@ -312,23 +457,25 @@ PropertyMap ASF::Tag::properties() const
props["COMMENT"] = d->comment;
}
for(const auto &[k, attributes] : std::as_const(d->attributeListMap)) {
const String key = translateKey(k);
ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin();
for(; it != d->attributeListMap.end(); ++it) {
const String key = translateKey(it->first);
if(!key.isEmpty()) {
for(const auto &attr : attributes) {
AttributeList::ConstIterator it2 = it->second.begin();
for(; it2 != it->second.end(); ++it2) {
if(key == "TRACKNUMBER") {
if(attr.type() == ASF::Attribute::DWordType)
props.insert(key, String::number(attr.toUInt()));
if(it2->type() == ASF::Attribute::DWordType)
props.insert(key, String::number(it2->toUInt()));
else
props.insert(key, attr.toString());
props.insert(key, it2->toString());
}
else {
props.insert(key, attr.toString());
props.insert(key, it2->toString());
}
}
}
else {
props.addUnsupportedData(k);
props.unsupportedData().append(it->first);
}
}
return props;
@@ -336,116 +483,70 @@ PropertyMap ASF::Tag::properties() const
void ASF::Tag::removeUnsupportedProperties(const StringList &props)
{
for(const auto &prop : props)
d->attributeListMap.erase(prop);
StringList::ConstIterator it = props.begin();
for(; it != props.end(); ++it)
d->attributeListMap.erase(*it);
}
PropertyMap ASF::Tag::setProperties(const PropertyMap &props)
{
static Map<String, String> reverseKeyMap;
if(reverseKeyMap.isEmpty()) {
for(const auto &[k, t] : keyTranslation) {
reverseKeyMap[t] = k;
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
for(int i = 0; i < numKeys; i++) {
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
}
}
const PropertyMap origProps = properties();
for(const auto &[prop, _] : origProps) {
if(!props.contains(prop) || props[prop].isEmpty()) {
if(prop == "TITLE") {
PropertyMap origProps = properties();
PropertyMap::ConstIterator it = origProps.begin();
for(; it != origProps.end(); ++it) {
if(!props.contains(it->first) || props[it->first].isEmpty()) {
if(it->first == "TITLE") {
d->title.clear();
}
else if(prop == "ARTIST") {
else if(it->first == "ARTIST") {
d->artist.clear();
}
else if(prop == "COMMENT") {
else if(it->first == "COMMENT") {
d->comment.clear();
}
else if(prop == "COPYRIGHT") {
else if(it->first == "COPYRIGHT") {
d->copyright.clear();
}
else {
d->attributeListMap.erase(reverseKeyMap[prop]);
d->attributeListMap.erase(reverseKeyMap[it->first]);
}
}
}
PropertyMap ignoredProps;
for(const auto &[prop, attributes] : props) {
if(reverseKeyMap.contains(prop)) {
String name = reverseKeyMap[prop];
it = props.begin();
for(; it != props.end(); ++it) {
if(reverseKeyMap.contains(it->first)) {
String name = reverseKeyMap[it->first];
removeItem(name);
for(const auto &attr : attributes) {
addAttribute(name, attr);
StringList::ConstIterator it2 = it->second.begin();
for(; it2 != it->second.end(); ++it2) {
addAttribute(name, *it2);
}
}
else if(prop == "TITLE") {
d->title = attributes.toString();
else if(it->first == "TITLE") {
d->title = it->second.toString();
}
else if(prop == "ARTIST") {
d->artist = attributes.toString();
else if(it->first == "ARTIST") {
d->artist = it->second.toString();
}
else if(prop == "COMMENT") {
d->comment = attributes.toString();
else if(it->first == "COMMENT") {
d->comment = it->second.toString();
}
else if(prop == "COPYRIGHT") {
d->copyright = attributes.toString();
else if(it->first == "COPYRIGHT") {
d->copyright = it->second.toString();
}
else {
ignoredProps.insert(prop, attributes);
ignoredProps.insert(it->first, it->second);
}
}
return ignoredProps;
}
StringList ASF::Tag::complexPropertyKeys() const
{
StringList keys;
if(d->attributeListMap.contains("WM/Picture")) {
keys.append("PICTURE");
}
return keys;
}
List<VariantMap> ASF::Tag::complexProperties(const String &key) const
{
List<VariantMap> props;
const String uppercaseKey = key.upper();
if(uppercaseKey == "PICTURE") {
const AttributeList pictures = d->attributeListMap.value("WM/Picture");
for(const Attribute &attr : pictures) {
ASF::Picture picture = attr.toPicture();
VariantMap property;
property.insert("data", picture.picture());
property.insert("mimeType", picture.mimeType());
property.insert("description", picture.description());
property.insert("pictureType",
ASF::Picture::typeToString(picture.type()));
props.append(property);
}
}
return props;
}
bool ASF::Tag::setComplexProperties(const String &key, const List<VariantMap> &value)
{
const String uppercaseKey = key.upper();
if(uppercaseKey == "PICTURE") {
removeItem("WM/Picture");
for(const auto &property : value) {
ASF::Picture picture;
picture.setPicture(property.value("data").value<ByteVector>());
picture.setMimeType(property.value("mimeType").value<String>());
picture.setDescription(property.value("description").value<String>());
picture.setType(ASF::Picture::typeFromString(
property.value("pictureType").value<String>()));
addAttribute("WM/Picture", Attribute(picture));
}
}
else {
return false;
}
return true;
}

View File

@@ -26,18 +26,18 @@
#ifndef TAGLIB_ASFTAG_H
#define TAGLIB_ASFTAG_H
#include "tag.h"
#include "tlist.h"
#include "tmap.h"
#include "taglib_export.h"
#include "tag.h"
#include "asfattribute.h"
namespace TagLib {
namespace ASF {
using AttributeList = List<Attribute>;
using AttributeListMap = Map<String, AttributeList>;
typedef List<Attribute> AttributeList;
typedef Map<String, AttributeList> AttributeListMap;
class TAGLIB_EXPORT Tag : public TagLib::Tag {
@@ -47,37 +47,34 @@ namespace TagLib {
Tag();
~Tag() override;
Tag(const Tag &) = delete;
Tag &operator=(const Tag &) = delete;
virtual ~Tag();
/*!
* Returns the track name.
*/
String title() const override;
virtual String title() const;
/*!
* Returns the artist name.
*/
String artist() const override;
virtual String artist() const;
/*!
* Returns the album name; if no album name is present in the tag
* String::null will be returned.
*/
String album() const override;
virtual String album() const;
/*!
* Returns the track comment.
*/
String comment() const override;
virtual String comment() const;
/*!
* Returns the genre name; if no genre is present in the tag String::null
* will be returned.
*/
String genre() const override;
virtual String genre() const;
/*!
* Returns the rating.
@@ -93,71 +90,73 @@ namespace TagLib {
/*!
* Returns the year; if there is no year set, this will return 0.
*/
unsigned int year() const override;
virtual unsigned int year() const;
/*!
* Returns the track number; if there is no track number set, this will
* return 0.
*/
unsigned int track() const override;
virtual unsigned int track() const;
virtual PictureMap pictures() const;
/*!
* Sets the title to \a value.
* Sets the title to \a s.
*/
void setTitle(const String &value) override;
virtual void setTitle(const String &s);
/*!
* Sets the artist to \a value.
* Sets the artist to \a s.
*/
void setArtist(const String &value) override;
virtual void setArtist(const String &s);
/*!
* Sets the album to \a value. If \a value is String::null then this value will be
* Sets the album to \a s. If \a s is String::null then this value will be
* cleared.
*/
void setAlbum(const String &value) override;
virtual void setAlbum(const String &s);
/*!
* Sets the comment to \a value.
* Sets the comment to \a s.
*/
void setComment(const String &value) override;
virtual void setComment(const String &s);
/*!
* Sets the rating to \a value.
* Sets the rating to \a s.
*/
virtual void setRating(const String &value);
virtual void setRating(const String &s);
/*!
* Sets the copyright to \a value.
* Sets the copyright to \a s.
*/
virtual void setCopyright(const String &value);
virtual void setCopyright(const String &s);
/*!
* Sets the genre to \a value.
* Sets the genre to \a s.
*/
void setGenre(const String &value) override;
virtual void setGenre(const String &s);
/*!
* Sets the year to \a value. If \a value is 0 then this value will be cleared.
* Sets the year to \a i. If \a s is 0 then this value will be cleared.
*/
void setYear(unsigned int value) override;
virtual void setYear(unsigned int i);
/*!
* Sets the track to \a value. If \a value is 0 then this value will be cleared.
* Sets the track to \a i. If \a s is 0 then this value will be cleared.
*/
void setTrack(unsigned int value) override;
virtual void setTrack(unsigned int i);
virtual void setPictures(const PictureMap &l);
/*!
* Returns true if the tag does not contain any data. This should be
* reimplemented in subclasses that provide more than the basic tagging
* abilities in this class.
*/
bool isEmpty() const override;
virtual bool isEmpty() const;
/*!
* \warning You should not modify this data structure directly, instead
* use attributeListMap() const, contains(), removeItem(),
* attribute(), setAttribute(), addAttribute().
* \deprecated
*/
AttributeListMap &attributeListMap();
@@ -168,14 +167,14 @@ namespace TagLib {
const AttributeListMap &attributeListMap() const;
/*!
* \return True if a value for \a key is currently set.
* \return True if a value for \a attribute is currently set.
*/
bool contains(const String &key) const;
bool contains(const String &name) const;
/*!
* Removes the \a key attribute from the tag
*/
void removeItem(const String &key);
void removeItem(const String &name);
/*!
* \return The list of values for the key \a name, or an empty list if no
@@ -184,8 +183,8 @@ namespace TagLib {
AttributeList attribute(const String &name) const;
/*!
* Sets the \a name attribute to the value of \a attribute. If an attribute
* with the \a name is already present, it will be replaced.
* Sets the \a key attribute to the value of \a attribute. If an attribute
* with the \a key is already present, it will be replaced.
*/
void setAttribute(const String &name, const Attribute &attribute);
@@ -195,25 +194,20 @@ namespace TagLib {
void setAttribute(const String &name, const AttributeList &values);
/*!
* Sets the \a name attribute to the value of \a attribute. If an attribute
* with the \a name is already present, it will be added to the list.
* Sets the \a key attribute to the value of \a attribute. If an attribute
* with the \a key is already present, it will be added to the list.
*/
void addAttribute(const String &name, const Attribute &attribute);
PropertyMap properties() const override;
void removeUnsupportedProperties(const StringList &props) override;
PropertyMap setProperties(const PropertyMap &props) override;
StringList complexPropertyKeys() const override;
List<VariantMap> complexProperties(const String &key) const override;
bool setComplexProperties(const String &key, const List<VariantMap> &value) override;
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList& properties);
PropertyMap setProperties(const PropertyMap &properties);
private:
class TagPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<TagPrivate> d;
TagPrivate *d;
};
} // namespace ASF
} // namespace TagLib
}
}
#endif

View File

@@ -37,7 +37,7 @@ namespace TagLib
namespace
{
inline unsigned short readWORD(File *file, bool *ok = nullptr)
inline unsigned short readWORD(File *file, bool *ok = 0)
{
const ByteVector v = file->readBlock(2);
if(v.size() != 2) {
@@ -45,10 +45,10 @@ namespace TagLib
return 0;
}
if(ok) *ok = true;
return v.toUShort(false);
return v.toUInt16LE(0);
}
inline unsigned int readDWORD(File *file, bool *ok = nullptr)
inline unsigned int readDWORD(File *file, bool *ok = 0)
{
const ByteVector v = file->readBlock(4);
if(v.size() != 4) {
@@ -56,10 +56,10 @@ namespace TagLib
return 0;
}
if(ok) *ok = true;
return v.toUInt(false);
return v.toUInt32LE(0);
}
inline long long readQWORD(File *file, bool *ok = nullptr)
inline long long readQWORD(File *file, bool *ok = 0)
{
const ByteVector v = file->readBlock(8);
if(v.size() != 8) {
@@ -67,13 +67,13 @@ namespace TagLib
return 0;
}
if(ok) *ok = true;
return v.toLongLong(false);
return v.toInt64LE(0);
}
inline String readString(File *file, int length)
{
ByteVector data = file->readBlock(length);
unsigned int size = data.size();
size_t size = data.size();
while (size >= 2) {
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
break;
@@ -88,16 +88,16 @@ namespace TagLib
inline ByteVector renderString(const String &str, bool includeLength = false)
{
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromUInt16LE(0);
if(includeLength) {
data = ByteVector::fromShort(data.size(), false) + data;
data = ByteVector::fromUInt16LE(data.size()) + data;
}
return data;
}
} // namespace
} // namespace ASF
} // namespace TagLib
}
}
}
#endif

View File

@@ -23,49 +23,34 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstringlist.h>
#include "audioproperties.h"
using namespace TagLib;
class AudioProperties::AudioPropertiesPrivate
{
};
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
AudioProperties::~AudioProperties() = default;
int AudioProperties::length() const
AudioProperties::~AudioProperties()
{
return lengthInSeconds();
}
int AudioProperties::lengthInSeconds() const
String AudioProperties::toString() const
{
return lengthInMilliseconds() / 1000;
}
int AudioProperties::lengthInMilliseconds() const
{
return 0;
}
int AudioProperties::bitrate() const
{
return 0;
}
int AudioProperties::sampleRate() const
{
return 0;
StringList desc;
desc.append("Audio");
desc.append(String::number(length()) + " seconds");
desc.append(String::number(bitrate()) + " kbps");
return desc.toString(", ");
}
////////////////////////////////////////////////////////////////////////////////
// protected methods
////////////////////////////////////////////////////////////////////////////////
AudioProperties::AudioProperties(ReadStyle)
AudioProperties::AudioProperties() :
d(0)
{
}

View File

@@ -26,10 +26,8 @@
#ifndef TAGLIB_AUDIOPROPERTIES_H
#define TAGLIB_AUDIOPROPERTIES_H
#include <memory>
#include "taglib.h"
#include "taglib_export.h"
#include "tstring.h"
namespace TagLib {
@@ -67,19 +65,10 @@ namespace TagLib {
*/
virtual ~AudioProperties();
AudioProperties(const AudioProperties &) = delete;
AudioProperties &operator=(const AudioProperties &) = delete;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated Use lengthInSeconds().
*/
TAGLIB_DEPRECATED
virtual int length() const;
* Returns the length of the file in seconds.
*/
virtual int length() const = 0;
/*!
* Returns the length of the file in seconds. The length is rounded down to
@@ -87,49 +76,55 @@ namespace TagLib {
*
* \see lengthInMilliseconds()
*/
virtual int lengthInSeconds() const;
virtual int lengthInSeconds() const = 0;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
virtual int lengthInMilliseconds() const;
virtual int lengthInMilliseconds() const = 0;
/*!
* Returns the most appropriate bit rate for the file in kb/s. For constant
* bitrate formats this is simply the bitrate of the file. For variable
* bitrate formats this is either the average or nominal bitrate.
*/
virtual int bitrate() const;
virtual int bitrate() const = 0;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
virtual int sampleRate() const = 0;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const = 0;
/*!
* Returns description of the audio file.
*/
virtual String toString() const;
protected:
/*!
* Construct an audio properties instance. This is protected as this class
* Constructs an audio properties instance. This is protected as this class
* should not be instantiated directly, but should be instantiated via its
* subclasses and can be fetched from the FileRef or File APIs.
*
* \see ReadStyle
*/
AudioProperties(ReadStyle style);
AudioProperties();
private:
class AudioPropertiesPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<AudioPropertiesPrivate> d;
// Noncopyable. Derived classes as well.
AudioProperties(const AudioProperties &);
AudioProperties &operator=(const AudioProperties &);
class PropertiesPrivate;
PropertiesPrivate *d;
};
} // namespace TagLib
}
#endif

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
@@ -24,12 +24,9 @@
***************************************************************************/
#include "dsdiffdiintag.h"
#include <utility>
#include "tstringlist.h"
#include "tpropertymap.h"
#include "tdebug.h"
#include "tpicturemap.h"
using namespace TagLib;
using namespace DSDIFF::DIIN;
@@ -37,16 +34,23 @@ using namespace DSDIFF::DIIN;
class DSDIFF::DIIN::Tag::TagPrivate
{
public:
TagPrivate()
{
}
String title;
String artist;
};
DSDIFF::DIIN::Tag::Tag() :
d(std::make_unique<TagPrivate>())
DSDIFF::DIIN::Tag::Tag() : TagLib::Tag()
{
d = new TagPrivate;
}
DSDIFF::DIIN::Tag::~Tag() = default;
DSDIFF::DIIN::Tag::~Tag()
{
delete d;
}
String DSDIFF::DIIN::Tag::title() const
{
@@ -83,6 +87,11 @@ unsigned int DSDIFF::DIIN::Tag::track() const
return 0;
}
PictureMap DSDIFF::DIIN::Tag::pictures() const
{
return PictureMap();
}
void DSDIFF::DIIN::Tag::setTitle(const String &title)
{
d->title = title;
@@ -95,27 +104,26 @@ void DSDIFF::DIIN::Tag::setArtist(const String &artist)
void DSDIFF::DIIN::Tag::setAlbum(const String &)
{
debug("DSDIFF::DIIN::Tag::setAlbum() -- Ignoring unsupported tag.");
}
void DSDIFF::DIIN::Tag::setComment(const String &)
{
debug("DSDIFF::DIIN::Tag::setComment() -- Ignoring unsupported tag.");
}
void DSDIFF::DIIN::Tag::setGenre(const String &)
{
debug("DSDIFF::DIIN::Tag::setGenre() -- Ignoring unsupported tag.");
}
void DSDIFF::DIIN::Tag::setYear(unsigned int)
{
debug("DSDIFF::DIIN::Tag::setYear() -- Ignoring unsupported tag.");
}
void DSDIFF::DIIN::Tag::setTrack(unsigned int)
{
debug("DSDIFF::DIIN::Tag::setTrack() -- Ignoring unsupported tag.");
}
void DSDIFF::DIIN::Tag::setPictures( const PictureMap& l )
{
}
PropertyMap DSDIFF::DIIN::Tag::properties() const
@@ -128,29 +136,31 @@ PropertyMap DSDIFF::DIIN::Tag::properties() const
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap props(origProps);
props.removeEmpty();
PropertyMap properties(origProps);
properties.removeEmpty();
StringList oneValueSet;
if(props.contains("TITLE")) {
d->title = props["TITLE"].front();
if(properties.contains("TITLE")) {
d->title = properties["TITLE"].front();
oneValueSet.append("TITLE");
} else
d->title.clear();
d->title = String();
if(props.contains("ARTIST")) {
d->artist = props["ARTIST"].front();
if(properties.contains("ARTIST")) {
d->artist = properties["ARTIST"].front();
oneValueSet.append("ARTIST");
} else
d->artist.clear();
d->artist = String();
// for each tag that has been set above, remove the first entry in the corresponding
// value list. The others will be returned as unsupported by this format.
for(const auto &entry : std::as_const(oneValueSet)) {
if(props[entry].size() == 1)
props.erase(entry);
for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
if(properties[*it].size() == 1)
properties.erase(*it);
else
props[entry].erase(props[entry].begin());
properties[*it].erase(properties[*it].begin());
}
return props;
return properties;
}

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
@@ -43,87 +43,97 @@ namespace TagLib {
{
public:
Tag();
~Tag() override;
virtual ~Tag();
/*!
* Returns the track name; if no track name is present in the tag
* String() will be returned.
*/
String title() const override;
virtual String title() const;
/*!
* Returns the artist name; if no artist name is present in the tag
* String() will be returned.
*/
String artist() const override;
virtual String artist() const;
/*!
* Not supported. Therefore always returns String().
*/
String album() const override;
virtual String album() const;
/*!
* Not supported. Therefore always returns String().
*/
String comment() const override;
virtual String comment() const;
/*!
* Not supported. Therefore always returns String().
*/
String genre() const override;
virtual String genre() const;
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int year() const override;
virtual unsigned int year() const;
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int track() const override;
virtual unsigned int track() const;
/*!
* Not supported. Therefore always returns an empty list.
*/
virtual PictureMap pictures() const;
/*!
* Sets the title to \a title. If \a title is String() then this
* value will be cleared.
*/
void setTitle(const String &title) override;
virtual void setTitle(const String &title);
/*!
* Sets the artist to \a artist. If \a artist is String() then this
* value will be cleared.
*/
void setArtist(const String &artist) override;
virtual void setArtist(const String &artist);
/*!
* Not supported and therefore ignored.
*/
void setAlbum(const String &album) override;
virtual void setAlbum(const String &album);
/*!
* Not supported and therefore ignored.
*/
void setComment(const String &comment) override;
virtual void setComment(const String &comment);
/*!
* Not supported and therefore ignored.
*/
void setGenre(const String &genre) override;
virtual void setGenre(const String &genre);
/*!
* Not supported and therefore ignored.
*/
void setYear(unsigned int year) override;
virtual void setYear(unsigned int year);
/*!
* Not supported and therefore ignored.
*/
void setTrack(unsigned int track) override;
virtual void setTrack(unsigned int track);
/*!
* Not supported and therefore ignored.
*/
virtual void setPictures( const PictureMap& l );
/*!
* Implements the unified property interface -- export function.
* Since the DIIN tag is very limited, the exported map is as well.
*/
PropertyMap properties() const override;
PropertyMap properties() const;
/*!
* Implements the unified property interface -- import function.
@@ -133,15 +143,18 @@ namespace TagLib {
* all but the first will be contained in the returned map of unsupported
* properties.
*/
PropertyMap setProperties(const PropertyMap &) override;
PropertyMap setProperties(const PropertyMap &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<TagPrivate> d;
TagPrivate *d;
};
} // namespace DIIN
} // namespace DSDIFF
} // namespace TagLib
}
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
@@ -42,7 +42,7 @@ namespace TagLib {
* chunk as well as properties from the file.
* Description of the DSDIFF format is available
* at http://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
* DSDIFF standard does not explicitly specify the ID3V2 chunk
* DSDIFF standard does not explictly specify the ID3V2 chunk
* It can be found at the root level, but also sometimes inside the PROP chunk
* In addition, title and artist info are stored as part of the standard
*/
@@ -61,55 +61,31 @@ namespace TagLib {
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* This set of flags is used for various operations and is suitable for
* being OR-ed together.
*/
enum TagTypes {
//! Empty set. Matches no tag types.
NoTags = 0x0000,
//! Matches DIIN tags.
DIIN = 0x0001,
//! Matches ID3v2 tags.
ID3v2 = 0x0002,
//! Matches all tag types.
AllTags = 0xffff
};
/*!
* Constructs a DSDIFF file from \a file. If \a readProperties is true
* Constructs an DSDIFF file from \a file. If \a readProperties is true
* the file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*
* If this file contains an ID3v2 tag, the frames will be created using
* \a frameFactory (default if null).
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average,
ID3v2::FrameFactory *frameFactory = nullptr);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Constructs an DSDIFF file from \a stream. If \a readProperties is true
* the file's audio properties will also be read.
*
* If this file contains an ID3v2 tag, the frames will be created using
* \a frameFactory (default if null).
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average,
ID3v2::FrameFactory *frameFactory = nullptr);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Destroys this instance of the File.
*/
~File() override;
virtual ~File();
/*!
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN
@@ -127,7 +103,7 @@ namespace TagLib {
* \see ID3v2Tag()
* \see DIINTag()
*/
Tag *tag() const override;
virtual Tag *tag() const;
/*!
* Returns the ID3V2 Tag for this file.
@@ -138,33 +114,33 @@ namespace TagLib {
*
* \see hasID3v2Tag()
*/
ID3v2::Tag *ID3v2Tag(bool create = false) const;
virtual ID3v2::Tag *ID3v2Tag() const;
/*!
* Returns the DSDIFF DIIN Tag for this file
*
*/
DSDIFF::DIIN::Tag *DIINTag(bool create = false) const;
DSDIFF::DIIN::Tag *DIINTag() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const override;
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties) override;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &) override;
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the AIFF::Properties for this file. If no audio properties
* Returns the DSDIFF::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Properties *audioProperties() const override;
virtual AudioProperties *audioProperties() const;
/*!
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this
@@ -181,24 +157,18 @@ namespace TagLib {
*
* \see save(int tags)
*/
bool save() override;
virtual bool save();
/*!
* Save the file. If \a strip is specified, it is possible to choose if
* tags not specified in \a tags should be stripped from the file or
* retained. With \a version, it is possible to specify whether ID3v2.4
* or ID3v2.3 should be used.
*/
bool save(int tags, StripTags strip = StripOthers, ID3v2::Version version = ID3v2::v4);
/*!
* 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.
* Save the file. This will attempt to save all of the tag types that are
* specified by OR-ing together TagTypes values. The save() method above
* uses AllTags. This returns true if saving was successful.
*
* \note This will update the file immediately.
* This strips all tags not included in the mask, but does not modify them
* in memory, so later calls to save() which make use of these tags will
* remain valid. This also strips empty tags.
*/
void strip(int tags = AllTags);
bool save(int tags);
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
@@ -209,7 +179,7 @@ namespace TagLib {
/*!
* Returns whether or not the file on disk actually has the DSDIFF
* title and artist tags.
* Title & Artist tag.
*
* \see DIINTag()
*/
@@ -231,10 +201,8 @@ namespace TagLib {
File(IOStream *stream, Endianness endianness);
private:
void removeRootChunk(const ByteVector &id);
void removeRootChunk(unsigned int i);
void removeChildChunk(const ByteVector &id, unsigned int childChunkNum);
void removeChildChunk(unsigned int i, unsigned int childChunkNum);
File(const File &);
File &operator=(const File &);
/*!
* Sets the data for the the specified chunk at root level to \a data.
@@ -277,16 +245,16 @@ namespace TagLib {
void updateRootChunksStructure(unsigned int startingChunk);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void read(bool readProperties, AudioProperties::ReadStyle propertiesStyle);
void writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace = 0,
unsigned int leadingPadding = 0);
class FilePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FilePrivate> d;
FilePrivate *d;
};
} // namespace DSDIFF
} // namespace TagLib
}
}
#endif

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
@@ -23,79 +23,95 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "dsdiffproperties.h"
#include <tstring.h>
#include <tdebug.h>
#include "tstring.h"
#include "tdebug.h"
#include "dsdiffproperties.h"
using namespace TagLib;
class DSDIFF::Properties::PropertiesPrivate
class DSDIFF::AudioProperties::AudioPropertiesPrivate
{
public:
int length { 0 };
int bitrate { 0 };
int sampleRate { 0 };
int channels { 0 };
int sampleWidth { 0 };
unsigned long long sampleCount { 0 };
AudioPropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
sampleWidth(0),
sampleCount(0)
{
}
int length;
int bitrate;
int sampleRate;
int channels;
int sampleWidth;
unsigned long long sampleCount;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSDIFF::Properties::Properties(const unsigned int sampleRate,
const unsigned short channels,
const unsigned long long samplesCount,
const int bitrate,
ReadStyle style) :
AudioProperties(style),
d(std::make_unique<PropertiesPrivate>())
DSDIFF::AudioProperties::AudioProperties(const unsigned int sampleRate,
const unsigned short channels,
const unsigned long long samplesCount,
const int bitrate,
ReadStyle style) : TagLib::AudioProperties(), d(new AudioPropertiesPrivate)
{
d->channels = channels;
d->channels = channels;
d->sampleCount = samplesCount;
d->sampleWidth = 1;
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5)
: 0;
}
DSDIFF::Properties::~Properties() = default;
DSDIFF::AudioProperties::~AudioProperties()
{
delete d;
}
int DSDIFF::Properties::lengthInSeconds() const
int DSDIFF::AudioProperties::length() const
{
return lengthInSeconds();
}
int DSDIFF::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int DSDIFF::Properties::lengthInMilliseconds() const
int DSDIFF::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int DSDIFF::Properties::bitrate() const
int DSDIFF::AudioProperties::bitrate() const
{
return d->bitrate;
}
int DSDIFF::Properties::sampleRate() const
int DSDIFF::AudioProperties::sampleRate() const
{
return d->sampleRate;
}
int DSDIFF::Properties::channels() const
int DSDIFF::AudioProperties::channels() const
{
return d->channels;
}
int DSDIFF::Properties::bitsPerSample() const
int DSDIFF::AudioProperties::bitsPerSample() const
{
return d->sampleWidth;
}
long long DSDIFF::Properties::sampleCount() const
long long DSDIFF::AudioProperties::sampleCount() const
{
return d->sampleCount;
}

View File

@@ -41,39 +41,43 @@ namespace TagLib {
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
public:
/*!
* Create an instance of DSDIFF::Properties with the data read from the
* Create an instance of DSDIFF::AudioProperties with the data read from the
* ByteVector \a data.
*/
Properties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
AudioProperties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
/*!
* Destroys this DSDIFF::Properties instance.
* Destroys this DSDIFF::AudioProperties instance.
*/
~Properties() override;
virtual ~AudioProperties();
// Reimplementations.
int lengthInSeconds() const override;
int lengthInMilliseconds() const override;
int bitrate() const override;
int sampleRate() const override;
int channels() const override;
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
int bitsPerSample() const;
long long sampleCount() const;
private:
class PropertiesPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<PropertiesPrivate> d;
AudioProperties(const AudioProperties &);
AudioProperties &operator=(const AudioProperties &);
class AudioPropertiesPrivate;
AudioPropertiesPrivate *d;
};
} // namespace DSDIFF
} // namespace TagLib
}
}
#endif

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2013-2023 Stephen F. Booth
email : me@sbooth.org
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
@@ -23,11 +23,15 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "dsffile.h"
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tsmartptr.h>
#include <tagutils.h>
#include "tdebug.h"
#include "tpropertymap.h"
#include "tagutils.h"
#include "dsffile.h"
using namespace TagLib;
@@ -36,58 +40,65 @@ using namespace TagLib;
class DSF::File::FilePrivate
{
public:
FilePrivate(ID3v2::FrameFactory *frameFactory)
: ID3v2FrameFactory(frameFactory ? frameFactory
: ID3v2::FrameFactory::instance())
{
}
FilePrivate() :
fileSize(0),
metadataOffset(0) {}
~FilePrivate() = default;
long long fileSize;
long long metadataOffset;
FilePrivate(const FilePrivate &) = delete;
FilePrivate &operator=(const FilePrivate &) = delete;
const ID3v2::FrameFactory *ID3v2FrameFactory;
long long fileSize = 0;
long long metadataOffset = 0;
std::unique_ptr<Properties> properties;
std::unique_ptr<ID3v2::Tag> tag;
SCOPED_PTR<AudioProperties> properties;
SCOPED_PTR<ID3v2::Tag> tag;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool DSF::File::isSupported(IOStream *stream)
{
// A DSF file has to start with "DSD "
const ByteVector id = Utils::readHeader(stream, 4, false);
return id.startsWith("DSD ");
// A DSF file has to start with "DSD "
const ByteVector id = Utils::readHeader(stream, 4, false);
return id.startsWith("DSD ");
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::File::File(FileName file, bool readProperties,
AudioProperties::ReadStyle propertiesStyle,
ID3v2::FrameFactory *frameFactory) :
AudioProperties::ReadStyle propertiesStyle) :
TagLib::File(file),
d(std::make_unique<FilePrivate>(frameFactory))
d(new FilePrivate())
{
if(isOpen())
read(propertiesStyle);
read(readProperties, propertiesStyle);
}
DSF::File::File(IOStream *stream, bool readProperties,
AudioProperties::ReadStyle propertiesStyle,
ID3v2::FrameFactory *frameFactory) :
AudioProperties::ReadStyle propertiesStyle) :
TagLib::File(stream),
d(std::make_unique<FilePrivate>(frameFactory))
d(new FilePrivate())
{
if(isOpen())
read(propertiesStyle);
read(readProperties, propertiesStyle);
}
DSF::File::~File() = default;
DSF::File::~File()
{
delete d;
}
ID3v2::Tag *DSF::File::tag() const
{
return d->tag.get();
}
DSF::AudioProperties *DSF::File::audioProperties() const
{
return d->properties.get();
}
PropertyMap DSF::File::properties() const
{
return d->tag->properties();
@@ -98,20 +109,15 @@ PropertyMap DSF::File::setProperties(const PropertyMap &properties)
return d->tag->setProperties(properties);
}
DSF::Properties *DSF::File::audioProperties() const
{
return d->properties.get();
}
bool DSF::File::save()
{
return save(ID3v2::v4);
}
bool DSF::File::save(ID3v2::Version version)
{
if(readOnly()) {
debug("DSF::File::save() - Cannot save to a read only file.");
debug("DSF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("DSF::File::save() -- Trying to save invalid file.");
return false;
}
@@ -122,13 +128,13 @@ bool DSF::File::save(ID3v2::Version version)
// Update the file size
if(d->fileSize != newFileSize) {
insert(ByteVector::fromLongLong(newFileSize, false), 12, 8);
insert(ByteVector::fromUInt64LE(newFileSize), 12, 8);
d->fileSize = newFileSize;
}
// Update the metadata offset to 0 since there is no longer a tag
if(d->metadataOffset) {
insert(ByteVector::fromLongLong(0ULL, false), 20, 8);
insert(ByteVector::fromUInt64LE(0ULL), 20, 8);
d->metadataOffset = 0;
}
@@ -136,7 +142,7 @@ bool DSF::File::save(ID3v2::Version version)
truncate(newFileSize);
}
else {
ByteVector tagData = d->tag->render(version);
ByteVector tagData = d->tag->render();
long long newMetadataOffset = d->metadataOffset ? d->metadataOffset : d->fileSize;
long long newFileSize = newMetadataOffset + tagData.size();
@@ -144,13 +150,13 @@ bool DSF::File::save(ID3v2::Version version)
// Update the file size
if(d->fileSize != newFileSize) {
insert(ByteVector::fromLongLong(newFileSize, false), 12, 8);
insert(ByteVector::fromUInt64LE(newFileSize), 12, 8);
d->fileSize = newFileSize;
}
// Update the metadata offset
if(d->metadataOffset != newMetadataOffset) {
insert(ByteVector::fromLongLong(newMetadataOffset, false), 20, 8);
insert(ByteVector::fromUInt64LE(newMetadataOffset), 20, 8);
d->metadataOffset = newMetadataOffset;
}
@@ -161,11 +167,12 @@ bool DSF::File::save(ID3v2::Version version)
return true;
}
void DSF::File::read(AudioProperties::ReadStyle propertiesStyle)
{
if(!isOpen())
return;
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSF::File::read(bool readProperties, AudioProperties::ReadStyle propertiesStyle)
{
// A DSF file consists of four chunks: DSD chunk, format chunk, data chunk, and metadata chunk
// The file format is not chunked in the sense of a RIFF File, though
@@ -177,25 +184,25 @@ void DSF::File::read(AudioProperties::ReadStyle propertiesStyle)
return;
}
long long dsdHeaderSize = readBlock(8).toLongLong(false);
long long chunkSize = readBlock(8).toInt64LE(0);
// Integrity check
if(dsdHeaderSize != 28) {
debug("DSF::File::read() -- File is corrupted, wrong DSD header size");
if(28 != chunkSize) {
debug("DSF::File::read() -- File is corrupted.");
setValid(false);
return;
}
d->fileSize = readBlock(8).toLongLong(false);
d->fileSize = readBlock(8).toInt64LE(0);
// File is malformed or corrupted, allow trailing garbage
if(d->fileSize > length()) {
debug("DSF::File::read() -- File is corrupted wrong length");
// File is malformed or corrupted
if(d->fileSize != length()) {
debug("DSF::File::read() -- File is corrupted.");
setValid(false);
return;
}
d->metadataOffset = readBlock(8).toLongLong(false);
d->metadataOffset = readBlock(8).toInt64LE(0);
// File is malformed or corrupted
if(d->metadataOffset > d->fileSize) {
@@ -212,21 +219,16 @@ void DSF::File::read(AudioProperties::ReadStyle propertiesStyle)
return;
}
long long fmtHeaderSize = readBlock(8).toLongLong(false);
if(fmtHeaderSize != 52) {
debug("DSF::File::read() -- File is corrupted, wrong FMT header size");
setValid(false);
return;
}
chunkSize = readBlock(8).toInt64LE(0);
d->properties = std::make_unique<Properties>(readBlock(fmtHeaderSize), propertiesStyle);
d->properties.reset(
new AudioProperties(readBlock(static_cast<size_t>(chunkSize)), propertiesStyle));
// Skip the data chunk
// A metadata offset of 0 indicates the absence of an ID3v2 tag
if(d->metadataOffset == 0)
d->tag = std::make_unique<ID3v2::Tag>(nullptr, 0, d->ID3v2FrameFactory);
if(0 == d->metadataOffset)
d->tag.reset(new ID3v2::Tag());
else
d->tag = std::make_unique<ID3v2::Tag>(this, d->metadataOffset,
d->ID3v2FrameFactory);
d->tag.reset(new ID3v2::Tag(this, d->metadataOffset));
}

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2013-2023 Stephen F. Booth
email : me@sbooth.org
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
@@ -26,111 +26,102 @@
#ifndef TAGLIB_DSFFILE_H
#define TAGLIB_DSFFILE_H
#include <memory>
#include "taglib_export.h"
#include "tfile.h"
#include "id3v2tag.h"
#include "dsfproperties.h"
#include "id3v2tag.h"
namespace TagLib {
//! An implementation of DSF metadata
/*!
* This is implementation of DSF metadata.
*
* This supports an ID3v2 tag as well as properties from the file.
*/
namespace DSF {
class TAGLIB_EXPORT File : public TagLib::File {
public:
/*!
* Constructs a DSD stream file from \a file.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
* read.
*
* If this file contains an ID3v2 tag, the frames will be created using
* \a frameFactory (default if null).
*/
File(FileName file, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average,
ID3v2::FrameFactory *frameFactory = nullptr);
/*!
* Constructs a DSD stream file from \a stream.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
* read.
*
* If this file contains an ID3v2 tag, the frames will be created using
* \a frameFactory (default if null).
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*/
File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average,
ID3v2::FrameFactory *frameFactory = nullptr);
//! An implementation of TagLib::File with DSF specific methods
/*!
* Destroys this instance of the File.
*/
~File() override;
/*!
* This implements and provides an interface for DSF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to DSF files.
*/
/*!
* Returns the ID3v2 Tag for this file.
*/
ID3v2::Tag *tag() const override;
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* Contructs an DSF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Implements the unified property interface -- export function.
* Forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const override;
/*!
* Contructs an DSF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Implements the unified property interface -- import function.
* Forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &) override;
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns the DSF::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Properties *audioProperties() const override;
/*!
* Returns the Tag for this file.
*/
virtual ID3v2::Tag *tag() const;
/*!
* Save the file.
*
* This returns true if the save was successful.
*/
bool save() override;
/*!
* Returns the DSF::AudioProperties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual AudioProperties *audioProperties() const;
/*!
* Save the file.
*
* \a version specifies the ID3v2 version to be used for writing tags.
*/
bool save(ID3v2::Version version);
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
virtual PropertyMap properties() const;
/*!
* Returns whether or not the given \a stream can be opened as a DSF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
virtual PropertyMap setProperties(const PropertyMap &);
private:
void read(AudioProperties::ReadStyle propertiesStyle);
/*!
* Saves the file.
*/
virtual bool save();
class FilePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FilePrivate> d;
/*!
* Returns whether or not the given \a stream can be opened as a DSF
* 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 &);
void read(bool readProperties, AudioProperties::ReadStyle propertiesStyle);
class FilePrivate;
FilePrivate *d;
};
} // namespace DSF
} // namespace TagLib
}
}
#endif

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2013-2023 Stephen F. Booth
email : me@sbooth.org
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
@@ -23,90 +23,115 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "dsfproperties.h"
using namespace TagLib;
class DSF::Properties::PropertiesPrivate
class DSF::AudioProperties::PropertiesPrivate
{
public:
PropertiesPrivate() = default;
~PropertiesPrivate() = default;
PropertiesPrivate(const PropertiesPrivate &) = delete;
PropertiesPrivate &operator=(const PropertiesPrivate &) = delete;
PropertiesPrivate() :
formatVersion(0),
formatID(0),
channelType(0),
channelNum(0),
samplingFrequency(0),
bitsPerSample(0),
sampleCount(0),
blockSizePerChannel(0),
bitrate(0),
length(0) {}
// Nomenclature is from DSF file format specification
unsigned int formatVersion = 0;
unsigned int formatID = 0;
unsigned int channelType = 0;
unsigned int channelNum = 0;
unsigned int samplingFrequency = 0;
unsigned int bitsPerSample = 0;
long long sampleCount = 0;
unsigned int blockSizePerChannel = 0;
unsigned int formatVersion;
unsigned int formatID;
unsigned int channelType;
unsigned int channelNum;
unsigned int samplingFrequency;
unsigned int bitsPerSample;
long long sampleCount;
unsigned int blockSizePerChannel;
// Computed
unsigned int bitrate = 0;
unsigned int length = 0;
int bitrate;
int length;
};
DSF::Properties::Properties(const ByteVector &data, ReadStyle style) :
AudioProperties(style),
d(std::make_unique<PropertiesPrivate>())
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::AudioProperties::AudioProperties(const ByteVector &data, ReadStyle style) :
d(new PropertiesPrivate())
{
read(data);
}
DSF::Properties::~Properties() = default;
DSF::AudioProperties::~AudioProperties()
{
delete d;
}
int DSF::Properties::lengthInMilliseconds() const
int DSF::AudioProperties::length() const
{
return lengthInSeconds();
}
int DSF::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int DSF::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int DSF::Properties::bitrate() const
int DSF::AudioProperties::bitrate() const
{
return d->bitrate;
}
int DSF::Properties::sampleRate() const
int DSF::AudioProperties::sampleRate() const
{
return d->samplingFrequency;
}
int DSF::Properties::channels() const
int DSF::AudioProperties::channels() const
{
return d->channelNum;
}
int DSF::Properties::formatVersion() const
// DSF specific
int DSF::AudioProperties::formatVersion() const
{
return d->formatVersion;
}
int DSF::Properties::formatID() const
int DSF::AudioProperties::formatID() const
{
return d->formatID;
}
int DSF::Properties::channelType() const
int DSF::AudioProperties::channelType() const
{
return d->channelType;
}
int DSF::Properties::bitsPerSample() const
int DSF::AudioProperties::bitsPerSample() const
{
return d->bitsPerSample;
}
long long DSF::Properties::sampleCount() const
long long DSF::AudioProperties::sampleCount() const
{
return d->sampleCount;
}
int DSF::Properties::blockSizePerChannel() const
int DSF::AudioProperties::blockSizePerChannel() const
{
return d->blockSizePerChannel;
}
@@ -115,20 +140,19 @@ int DSF::Properties::blockSizePerChannel() const
// private members
////////////////////////////////////////////////////////////////////////////////
void DSF::Properties::read(const ByteVector &data)
void DSF::AudioProperties::read(const ByteVector &data)
{
d->formatVersion = data.toUInt(0U,false);
d->formatID = data.toUInt(4U,false);
d->channelType = data.toUInt(8U,false);
d->channelNum = data.toUInt(12U,false);
d->samplingFrequency = data.toUInt(16U,false);
d->bitsPerSample = data.toUInt(20U,false);
d->sampleCount = data.toLongLong(24U,false);
d->blockSizePerChannel = data.toUInt(32U,false);
d->formatVersion = data.toUInt32LE(0);
d->formatID = data.toUInt32LE(4);
d->channelType = data.toUInt32LE(8);
d->channelNum = data.toUInt32LE(12);
d->samplingFrequency = data.toUInt32LE(16);
d->bitsPerSample = data.toUInt32LE(20);
d->sampleCount = data.toInt64LE(24);
d->blockSizePerChannel = data.toUInt32LE(32);
d->bitrate = static_cast<unsigned int>(
(d->samplingFrequency * d->bitsPerSample * d->channelNum) / 1000.0 + 0.5);
d->length = d->samplingFrequency > 0
? static_cast<unsigned int>(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5)
: 0;
d->bitrate = static_cast<int>(d->samplingFrequency * d->bitsPerSample * d->channelNum / 1000.0 + 0.5);
if(d->samplingFrequency > 0)
d->length = static_cast<int>(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5);
}

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2013-2023 Stephen F. Booth
email : me@sbooth.org
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
@@ -26,26 +26,43 @@
#ifndef TAGLIB_DSFPROPERTIES_H
#define TAGLIB_DSFPROPERTIES_H
#include <memory>
#include "taglib_export.h"
#include "tbytevector.h"
#include "audioproperties.h"
namespace TagLib {
namespace DSF {
class TAGLIB_EXPORT Properties : public AudioProperties {
class File;
//! An implementation of audio property reading for DSF
/*!
* This reads the data from a DSF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
public:
Properties(const ByteVector &data, ReadStyle style);
~Properties() override;
/*!
* Create an instance of DSF::AudioProperties with the data read from the
* ByteVector \a data.
*/
AudioProperties(const ByteVector &data, ReadStyle style);
Properties(const Properties &) = delete;
Properties &operator=(const Properties &) = delete;
/*!
* Destroys this DSF::AudioProperties instance.
*/
virtual ~AudioProperties();
int lengthInMilliseconds() const override;
int bitrate() const override;
int sampleRate() const override;
int channels() const override;
// Reimplementations.
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
int formatVersion() const;
int formatID() const;
@@ -60,13 +77,15 @@ namespace TagLib {
int blockSizePerChannel() const;
private:
AudioProperties(const AudioProperties &);
AudioProperties &operator=(const AudioProperties &);
void read(const ByteVector &data);
class PropertiesPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<PropertiesPrivate> d;
PropertiesPrivate *d;
};
} // namespace DSF
} // namespace TagLib
}
}
#endif

View File

@@ -1,6 +1,6 @@
/***************************************************************************
copyright : (C) 2023 by Urs Fleisch
email : ufleisch@users.sourceforge.net
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
@@ -23,54 +23,36 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "tpicturetype.h"
#ifndef TAGLIB_EBML_CONSTANTS
#define TAGLIB_EBML_CONSTANTS
#include "tstring.h"
namespace TagLib {
using namespace TagLib;
namespace {
constexpr const char *typeStrs[] = {
"Other",
"File Icon",
"Other File Icon",
"Front Cover",
"Back Cover",
"Leaflet Page",
"Media",
"Lead Artist",
"Artist",
"Conductor",
"Band",
"Composer",
"Lyricist",
"Recording Location",
"During Recording",
"During Performance",
"Movie Screen Capture",
"Coloured Fish",
"Illustration",
"Band Logo",
"Publisher Logo",
};
} // namespace
String Utils::pictureTypeToString(int type)
{
if(type >= 0 && type < static_cast<int>(std::size(typeStrs))) {
return typeStrs[type];
}
return "";
}
int Utils::pictureTypeFromString(const String& str)
{
for(int i = 0; i < static_cast<int>(std::size(typeStrs)); ++i) {
if(str == typeStrs[i]) {
return i;
namespace EBML {
//! Shorter representation of the type.
typedef unsigned long long int ulli;
//! The id of an EBML Void element that is just a placeholder.
const ulli Void = 0xecL;
//! The id of an EBML CRC32 element that contains a crc32 value.
const ulli CRC32 = 0xc3L;
//! A namespace containing the ids of the EBML header's elements.
namespace Header {
const ulli EBML = 0x1a45dfa3L;
const ulli EBMLVersion = 0x4286L;
const ulli EBMLReadVersion = 0x42f7L;
const ulli EBMLMaxIDWidth = 0x42f2L;
const ulli EBMLMaxSizeWidth = 0x42f3L;
const ulli DocType = 0x4282L;
const ulli DocTypeVersion = 0x4287L;
const ulli DocTypeReadVersion = 0x4285L;
}
}
return 0;
}
#endif

489
taglib/ebml/ebmlelement.cpp Normal file
View File

@@ -0,0 +1,489 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "tdebug.h"
#include "ebmlelement.h"
using namespace TagLib;
class EBML::Element::ElementPrivate
{
public:
// The id of this element.
ulli id;
// The position of the element, where the header begins.
long long position;
// The size of the element as read from the header. Note: Actually an ulli but
// due to the variable integer size limited, thus long long is ok.
long long size;
// The position of the element's data.
long long data;
// The element's children.
List<Element *> children;
// True: Treated this element as container and read children.
bool populated;
// The parent element. If NULL (0) this is the document root.
Element *parent;
// The file used to read and write.
File *document;
// Destructor: Clean up all children.
~ElementPrivate()
{
for(List<Element *>::Iterator i = children.begin(); i != children.end(); ++i) {
delete *i;
}
}
// Reads a variable length integer from the file at the given position
// and saves its value to result. If cutOne is true the first one of the
// binary representation of the result is removed (required for size). If
// cutOne is false the one will remain in the result (required for id).
// This method returns the position directly after the read integer.
long long readVInt(long long position, ulli *result, bool cutOne = true)
{
document->seek(position);
// Determine the length of the integer
char firstByte = document->readBlock(1)[0];
size_t byteSize = 1;
for(size_t i = 0; i < 8 && ((firstByte << i) & (1 << 7)) == 0; ++i)
++byteSize;
// Load the integer
document->seek(position);
ByteVector vint = document->readBlock(byteSize);
// Cut the one if requested
if(cutOne)
vint[0] = (vint[0] & (~(1 << (8 - byteSize))));
// Store the result and return the current position
if(result)
*result = static_cast<ulli>(vint.toInt64BE(0));
return position + byteSize;
}
// Returns a BytVector containing the given number in the variable integer
// format. Truncates numbers > 2^56 (^ means potency in this case).
// If addOne is true, the ByteVector will remain the One to determine the
// integer's length.
// If shortest is true, the ByteVector will be as short as possible (required
// for the id)
ByteVector createVInt(ulli number, bool addOne = true, bool shortest = true)
{
ByteVector vint = ByteVector::fromUInt64BE(number);
// Do we actually need to calculate the length of the variable length
// integer? If not, then prepend the 0b0000 0001 if necessary and return the
// vint.
if(!shortest) {
if(addOne)
vint[0] = 1;
return vint;
}
// Calculate the minimal length of the variable length integer
size_t byteSize = vint.size();
for(size_t i = 0; byteSize > 0 && vint[i] == 0; ++i)
--byteSize;
if(!addOne)
return ByteVector(vint.data() + vint.size() - byteSize, byteSize);
ulli firstByte = (1ULL << (vint.size() - byteSize));
// The most significant byte loses #bytSize bits for storing information.
// Therefore, we might need to increase byteSize.
if(number >= (firstByte << (8 * (byteSize - 1))) && byteSize < vint.size())
++byteSize;
// Add the one at the correct position
size_t firstBytePosition = vint.size() - byteSize;
vint[firstBytePosition] |= (1 << firstBytePosition);
return ByteVector(vint.data() + firstBytePosition, byteSize);
}
// Returns a void element within this element which is at least "least" in
// size. Uses best fit method. Returns a null pointer if no suitable element
// was found.
Element *searchVoid(long long least = 0L)
{
Element *currentBest = 0;
for(List<Element *>::Iterator i = children.begin(); i != children.end(); ++i) {
if((*i)->d->id == Void &&
// We need room for the header if we don't remove the element.
((((*i)->d->size + (*i)->d->data - (*i)->d->position) == least || ((*i)->d->size >= least)) &&
// best fit
(!currentBest || (*i)->d->size < currentBest->d->size))
) {
currentBest = *i;
}
}
return currentBest;
}
// Replaces this element by a Void element. Returns true on success and false
// on error.
bool makeVoid()
{
ulli realSize = size + data - position;
ByteVector header(createVInt(Void, false));
ulli leftSize = realSize - (header.size() + sizeof(ulli));
// Does not make sense to create a Void element
if (leftSize > realSize)
return false;
header.append(createVInt(leftSize, true, false));
// Write to file
document->seek(position);
document->writeBlock(header);
// Update data
data = position + header.size();
size = leftSize;
return true;
// XXX: We actually should merge Voids, if possible.
}
// Reading constructor: Reads all unknown information from the file.
ElementPrivate(File *p_document, Element *p_parent = 0, long long p_position = 0) :
id(0),
position(p_position),
data(0),
populated(false),
parent(p_parent),
document(p_document)
{
if(parent) {
ulli ssize;
data = readVInt(readVInt(position, &id, false), &ssize);
size = static_cast<long long>(ssize);
}
else {
document->seek(0, File::End);
size = document->tell();
}
}
// Writing constructor: Takes given information, calculates missing information
// and writes everything to the file.
// Tries to use void elements if available in the parent.
ElementPrivate(ulli p_id, File *p_document, Element *p_parent,
long long p_position, long long p_size) :
id(p_id),
position(p_position),
size(p_size),
populated(true), // It is a new element so we know, there are no children.
parent(p_parent),
document(p_document)
{
// header
ByteVector content(createVInt(id, false).append(createVInt(size, true, false)));
data = position + content.size();
// space for children
content.resize(static_cast<size_t>(data - position + size));
Element *freeSpace;
if (!(freeSpace = searchVoid(content.size()))) {
// We have to make room
document->insert(content, position);
// Update parents
for(Element *current = parent; current->d->parent; current = current->d->parent) {
current->d->size += content.size();
// Create new header and write it.
ByteVector parentHeader(createVInt(current->d->id, false).append(createVInt(current->d->size, true, false)));
size_t oldHeaderSize = static_cast<size_t>(current->d->data - current->d->position);
if(oldHeaderSize < parentHeader.size()) {
ByteVector secondHeader(createVInt(current->d->id, false).append(createVInt(current->d->size)));
if(oldHeaderSize == secondHeader.size()) {
// Write the header where the old one was.
document->seek(current->d->position);
document->writeBlock(secondHeader);
continue; // Very important here!
}
}
// Insert the new header
document->insert(parentHeader, current->d->position, oldHeaderSize);
current->d->data = current->d->position + parentHeader.size();
}
}
else {
document->seek(freeSpace->d->position);
if((freeSpace->d->size + freeSpace->d->data - freeSpace->d->position)
== static_cast<long long>(content.size())) {
// Write to file
document->writeBlock(content);
// Update parent
for(List<Element *>::Iterator i = parent->d->children.begin();
i != parent->d->children.end(); ++i) {
if(freeSpace == *i)
parent->d->children.erase(i);
}
delete freeSpace;
}
else {
ulli newSize = freeSpace->d->size - content.size();
ByteVector newVoid(createVInt(Void, false).append(createVInt(newSize, true, false)));
// Check if the original size of the size field was really 8 byte
if (static_cast<long long>(newVoid.size()) != (freeSpace->d->data - freeSpace->d->position))
newVoid = createVInt(Void, false).append(createVInt(newSize));
// Update freeSpace
freeSpace->d->size = newSize;
freeSpace->d->data = freeSpace->d->position + newVoid.size();
// Write to file
document->writeBlock(
newVoid.resize(static_cast<size_t>(newVoid.size() + newSize)).append(content));
}
}
}
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
EBML::Element::~Element()
{
delete d;
}
EBML::Element::Element(EBML::File *document)
: d(new EBML::Element::ElementPrivate(document))
{
}
EBML::Element *EBML::Element::getChild(EBML::ulli id)
{
populate();
for(List<Element *>::Iterator i = d->children.begin(); i != d->children.end();
++i) {
if ((*i)->d->id == id)
return *i;
}
return 0;
}
List<EBML::Element *> EBML::Element::getChildren(EBML::ulli id)
{
populate();
List<Element *> result;
for(List<Element *>::Iterator i = d->children.begin(); i != d->children.end();
++i) {
if ((*i)->d->id == id)
result.append(*i);
}
return result;
}
List<EBML::Element *> EBML::Element::getChildren()
{
populate();
return d->children;
}
EBML::Element *EBML::Element::getParent()
{
return d->parent;
}
ByteVector EBML::Element::getAsBinary()
{
d->document->seek(d->data);
return d->document->readBlock(static_cast<size_t>(d->size));
}
String EBML::Element::getAsString()
{
return String(getAsBinary(), String::UTF8);
}
long long EBML::Element::getAsInt()
{
// The debug note about returning 0 because of empty data is irrelevant. The
// behavior is as expected.
return getAsBinary().toInt64BE(0);
}
EBML::ulli EBML::Element::getAsUnsigned()
{
// The debug note about returning 0 because of empty data is irrelevant. The
// behavior is as expected.
return static_cast<ulli>(getAsBinary().toInt64BE(0));
}
long double EBML::Element::getAsFloat()
{
const ByteVector bin = getAsBinary();
switch (bin.size())
{
case 4:
return bin.toFloat32BE(0);
case 8:
return bin.toFloat64BE(0);
case 10:
return bin.toFloat80BE(0);
default:
debug("EBML::Element::getAsFloat() - Invalid data size. Returning 0.");
return 0.0;
}
}
EBML::Element *EBML::Element::addElement(EBML::ulli id)
{
Element *elem = new Element(
new ElementPrivate(id, d->document, this, d->data + d->size, 0)
);
d->children.append(elem);
return elem;
}
EBML::Element *EBML::Element::addElement(EBML::ulli id, const ByteVector &binary)
{
Element *elem = new Element(
new ElementPrivate(id, d->document, this, d->data + d->size, binary.size())
);
d->document->seek(elem->d->data);
d->document->writeBlock(binary);
d->children.append(elem);
return elem;
}
EBML::Element *EBML::Element::addElement(EBML::ulli id, const String &string)
{
return addElement(id, string.data(String::UTF8));
}
EBML::Element *EBML::Element::addElement(EBML::ulli id, signed long long number)
{
return addElement(id, ByteVector::fromUInt64BE(number));
}
EBML::Element *EBML::Element::addElement(EBML::ulli id, EBML::ulli number)
{
return addElement(id, ByteVector::fromUInt64BE(number));
}
EBML::Element *EBML::Element::addElement(EBML::ulli id, long double number)
{
// Probably, we will never need this method.
return 0;
}
bool EBML::Element::removeChildren(EBML::ulli id, bool useVoid)
{
bool result = false;
for(List<Element *>::Iterator i = d->children.begin(); i != d->children.end(); ++i)
if((*i)->d->id == id) {
removeChild(*i, useVoid);
result = true;
}
return result;
}
bool EBML::Element::removeChildren(bool useVoid)
{
// Maybe a better implementation, because we probably create a lot of voids
// in a row where a huge Void would be more appropriate.
if (d->children.isEmpty())
return false;
for(List<Element *>::Iterator i = d->children.begin(); i != d->children.end(); ++i)
removeChild(*i, useVoid);
return true;
}
bool EBML::Element::removeChild(Element *element, bool useVoid)
{
if (!d->children.contains(element))
return false;
if(!useVoid || !element->d->makeVoid()) {
d->document->removeBlock(element->d->position, static_cast<size_t>(element->d->size));
// Update parents
for(Element* current = this; current; current = current->d->parent)
current->d->size -= element->d->size;
// Update this element
for(List<Element *>::Iterator i = d->children.begin(); i != d->children.end(); ++i)
if(element == *i)
d->children.erase(i);
delete element;
}
return true;
}
void EBML::Element::setAsBinary(const ByteVector &binary)
{
// Maybe: Search for void element after this one
d->document->insert(binary, d->data, static_cast<size_t>(d->size));
}
void EBML::Element::setAsString(const String &string)
{
setAsBinary(string.data(String::UTF8));
}
void EBML::Element::setAsInt(signed long long number)
{
setAsBinary(ByteVector::fromUInt64BE(number));
}
void EBML::Element::setAsUnsigned(EBML::ulli number)
{
setAsBinary(ByteVector::fromUInt64BE(number));
}
void EBML::Element::setAsFloat(long double)
{
// Probably, we will never need this method.
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void EBML::Element::populate()
{
if(!d->populated) {
d->populated = true;
long long end = d->data + d->size;
for(long long i = d->data; i < end;) {
Element *elem = new Element(
new ElementPrivate(d->document, this, i)
);
d->children.append(elem);
i = elem->d->data + elem->d->size;
}
}
}
EBML::Element::Element(EBML::Element::ElementPrivate *pe) : d(pe)
{}

276
taglib/ebml/ebmlelement.h Normal file
View File

@@ -0,0 +1,276 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_EBMLELEMENT_H
#define TAGLIB_EBMLELEMENT_H
#include "tlist.h"
#include "tbytevector.h"
#include "tstring.h"
#include "ebmlfile.h"
namespace TagLib {
namespace EBML {
/*!
* Represents an element of the EBML. The only instance of this child, that
* is directly used is the root element. Every other element is accessed
* via pointers to the elements within the root element.
*
* Just create one root instance per file to prevent race conditions.
*
* Changes of the document tree will be directly written back to the file.
* Invalid values (exceeding the maximal value defined in the RFC) will be
* truncated.
*
* This class should not be used by library users since the proper file
* class should handle the internals.
*
* NOTE: Currently does not adjust CRC32 values.
*/
class TAGLIB_EXPORT Element
{
public:
//! Destroys the instance of the element.
~Element();
/*!
* Creates an root element using document.
*/
explicit Element(File *document);
/*!
* Returns the first found child element with the given id. Returns a null
* pointer if the child does not exist.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
Element *getChild(const ulli id);
/*!
* Returns a list of all child elements with the given id. Returns an
* empty list if no such element exists.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
List<Element *> getChildren(const ulli id);
/*!
* Returns a list of every child elements available. Returns an empty list
* if there are no children.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
List<Element *> getChildren();
/*!
* Returns the parent element or null if no such element exists.
*/
Element *getParent();
/*!
* Returns the raw content of the element.
*/
ByteVector getAsBinary();
/*!
* Returns the content of this element interpreted as a string.
*/
String getAsString();
/*!
* Returns the content of this element interpreted as an signed integer.
*
* Do not call this method if *this element is not an INT element (see
* corresponding DTD)
*/
long long getAsInt();
/*!
* Returns the content of this element interpreted as an unsigned integer.
*
* Do not call this method if *this element is not an UINT element (see
* corresponding DTD)
*/
ulli getAsUnsigned();
/*!
* Returns the content of this element interpreted as a floating point
* type.
*
* Do not call this method if *this element is not an FLOAT element (see
* corresponding DTD)
*
* NOTE: There are 10 byte floats defined, therefore we might need a long
* double to store the value.
*/
long double getAsFloat();
/*!
* Adds an empty element with given id to this element. Returns a pointer
* to the new element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
Element *addElement(ulli id);
/*!
* Adds a new element, containing the given binary, to this element.
* Returns a pointer to the new element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
Element *addElement(ulli id, const ByteVector &binary);
/*!
* Adds a new element, containing the given string, to this element.
* Returns a pointer to the new element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
Element *addElement(ulli id, const String &string);
/*!
* Adds a new element, containing the given integer, to this element.
* Returns a pointer to the new element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
Element *addElement(ulli id, signed long long number);
/*!
* Adds a new element, containing the given unsigned integer, to this element.
* Returns a pointer to the new element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*/
Element *addElement(ulli id, ulli number);
/*!
* Adds a new element, containing the given floating point value, to this element.
* Returns a pointer to the new element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*
* This method is not implemented!
*/
Element *addElement(ulli id, long double number);
/*!
* Removes all children with the given id. Returns false if there was no
* such element.
* If useVoid is true, the element will be changed to a void element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*
* Every pointer to a removed element is invalidated.
*/
bool removeChildren(ulli id, bool useVoid = true);
/*!
* Removes all children. Returns false if this element had no children.
* If useVoid ist rue, the element will be changed to a void element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*
* Every pointer to a removed element is invalidated.
*/
bool removeChildren(bool useVoid = true);
/*!
* Removes the given element.
* If useVoid is true, the element will be changed to a void element.
*
* Do not call this method if *this element is not a container element (see
* corresponding DTD)
*
* The pointer to the given element is invalidated.
*/
bool removeChild(Element *element, bool useVoid = true);
/*!
* Writes the given binary to this element.
*/
void setAsBinary(const ByteVector &binary);
/*!
* Writes the given string to this element.
*/
void setAsString(const String &string);
/*!
* Writes the given integer to this element.
*/
void setAsInt(signed long long number);
/*!
* Writes the given unsigned integer to this element.
*/
void setAsUnsigned(ulli number);
/*!
* Writes the given floating point variable to this element.
*
* This method is not implemented!
*/
void setAsFloat(long double number);
private:
//! Non-copyable
Element(const Element &);
//! Non-copyable
Element &operator=(const File &);
//! Lazy parsing. This method will be triggered when trying to access
//! children.
void populate();
class ElementPrivate;
ElementPrivate *d;
//! Creates a new Element from an ElementPrivate. (The constructor takes
//! ownership of the pointer and will delete it when the element is
//! destroyed.
Element(ElementPrivate *pe);
};
}
}
#endif

102
taglib/ebml/ebmlfile.cpp Normal file
View File

@@ -0,0 +1,102 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "ebmlelement.h"
using namespace TagLib;
class EBML::File::FilePrivate
{
public:
explicit FilePrivate(File *document) : root(document)
{
}
// Performs a few basic checks and creates the FilePrivate if they were
// successful.
static FilePrivate *checkAndCreate(File* document)
{
document->seek(0);
ByteVector magical = document->readBlock(4);
if(static_cast<ulli>(magical.toUInt32BE(0)) != Header::EBML)
return 0;
FilePrivate *d = new FilePrivate(document);
Element *head = d->root.getChild(Header::EBML);
Element *p;
if(!head ||
!((p = head->getChild(Header::EBMLVersion)) && p->getAsUnsigned() == 1L) ||
!((p = head->getChild(Header::EBMLReadVersion)) && p->getAsUnsigned() == 1L) ||
// Actually 4 is the current maximum of the EBML spec, but we support up to 8
!((p = head->getChild(Header::EBMLMaxIDWidth)) && p->getAsUnsigned() <= 8) ||
!((p = head->getChild(Header::EBMLMaxSizeWidth)) && p->getAsUnsigned() <= 8)
) {
delete d;
return 0;
}
return d;
}
Element root;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
EBML::File::~File()
{
delete d;
}
EBML::Element *EBML::File::getDocumentRoot()
{
if(!d && isValid())
d = new FilePrivate(this);
return &d->root;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
EBML::File::File(FileName file) :
TagLib::File(file)
{
if(isOpen()) {
d = FilePrivate::checkAndCreate(this);
if(!d)
setValid(false);
}
}
EBML::File::File(IOStream *stream) :
TagLib::File(stream)
{
if(isOpen()) {
d = FilePrivate::checkAndCreate(this);
if(!d)
setValid(false);
}
}

86
taglib/ebml/ebmlfile.h Normal file
View File

@@ -0,0 +1,86 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_EBMLFILE_H
#define TAGLIB_EBMLFILE_H
#include "taglib_export.h"
#include "tfile.h"
#include "ebmlconstants.h"
namespace TagLib {
//! A namespace for the classes used by EBML-based metadata files
namespace EBML {
class Element;
/*!
* Represents an EBML file. It offers access to the root element which can
* be used to obtain the necessary information and to change the file
* according to changes.
*/
class TAGLIB_EXPORT File : public TagLib::File
{
public:
//! Destroys the instance of the file.
virtual ~File();
/*!
* Returns a pointer to the document root element of the EBML file.
*/
Element *getDocumentRoot();
protected:
/*!
* Constructs an instance of an EBML file from \a file.
*
* This constructor is protected since an object should be created
* through a specific subclass.
*/
explicit File(FileName file);
/*!
* Constructs an instance of an EBML file from an IOStream.
*
* This constructor is protected since an object should be created
* through a specific subclass.
*/
explicit File(IOStream *stream);
private:
//! Non-copyable
File(const File&);
File &operator=(const File &);
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

View File

@@ -0,0 +1,135 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "ebmlmatroskaconstants.h"
#include "ebmlmatroskaaudio.h"
using namespace TagLib;
class EBML::Matroska::AudioProperties::AudioPropertiesPrivate
{
public:
// Constructor
AudioPropertiesPrivate() :
length(0),
bitrate(0),
channels(1),
samplerate(8000) {}
// The length of the file
int length;
// The bitrate
int bitrate;
// The amount of channels
int channels;
// The sample rate
int samplerate;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
EBML::Matroska::AudioProperties::AudioProperties(File *document) :
d(new AudioPropertiesPrivate())
{
read(document);
}
EBML::Matroska::AudioProperties::~AudioProperties()
{
delete d;
}
int EBML::Matroska::AudioProperties::length() const
{
return lengthInSeconds();
}
int EBML::Matroska::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int EBML::Matroska::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int EBML::Matroska::AudioProperties::bitrate() const
{
return d->bitrate;
}
int EBML::Matroska::AudioProperties::channels() const
{
return d->channels;
}
int EBML::Matroska::AudioProperties::sampleRate() const
{
return d->samplerate;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void EBML::Matroska::AudioProperties::read(File *document)
{
Element *elem = document->getDocumentRoot()->getChild(Constants::Segment);
Element *info = elem->getChild(Constants::SegmentInfo);
Element *value;
if(info && (value = info->getChild(Constants::Duration))) {
const double length = value->getAsFloat() / 1000000.0;
if((value = info->getChild(Constants::TimecodeScale)))
d->length = static_cast<int>(length * value->getAsUnsigned() + 0.5);
else
d->length = static_cast<int>(length * 1000000 + 0.5);
}
info = elem->getChild(Constants::Tracks);
if(!info || !(info = info->getChild(Constants::TrackEntry)) ||
!(info = info->getChild(Constants::Audio))) {
return;
}
// Dirty bitrate:
if(d->length > 0)
d->bitrate = static_cast<int>(document->length() * 8.0 / d->length + 0.5);
if((value = info->getChild(Constants::Channels)))
d->channels = static_cast<int>(value->getAsUnsigned());
if((value = info->getChild(Constants::SamplingFrequency)))
d->samplerate = static_cast<int>(value->getAsFloat());
}

View File

@@ -0,0 +1,92 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_EBMLMATROSKAAUDIO_H
#define TAGLIB_EBMLMATROSKAAUDIO_H
#include "ebmlmatroskafile.h"
#include "audioproperties.h"
namespace TagLib {
namespace EBML {
namespace Matroska {
/*!
* This class represents the audio properties of a matroska file.
* Currently all information are read from the container format and
* could be inexact.
*/
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
public:
//! Destructor
virtual ~AudioProperties();
/*!
* Constructs an instance from a file.
*/
explicit AudioProperties(File *document);
/*!
* Returns the length of the file.
*/
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
/*!
* Returns the bit rate of the file. Since the container format does not
* offer a proper value, it ist currently calculated by dividing the
* file size by the length.
*/
virtual int bitrate() const;
/*!
* Returns the amount of channels of the file.
*/
virtual int channels() const;
/*!
* Returns the sample rate of the file.
*/
virtual int sampleRate() const;
private:
void read(File *document);
class AudioPropertiesPrivate;
AudioPropertiesPrivate *d;
};
}
}
}
#endif

View File

@@ -0,0 +1,140 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_EBMLMATROSKACONSTANTS_H
#define TAGLIB_EBMLMATROSKACONSTANTS_H
#include "ebmlconstants.h"
#include "tstring.h"
namespace TagLib {
namespace EBML {
namespace Matroska {
namespace Constants {
//! ID of an Matroska segment.
const ulli Segment = 0x18538067L;
//! ID of the tags element.
const ulli Tags = 0x1254c367L;
//! ID of the tag element.
const ulli Tag = 0x7373L;
//! ID of the targets element.
const ulli Targets = 0x63c0L;
//! ID of the target type value element.
const ulli TargetTypeValue = 0x68caL;
//! ID of the target type element.
const ulli TargetType = 0x63caL;
//! ID of a simple tag element.
const ulli SimpleTag = 0x67c8L;
//! ID of the tag name.
const ulli TagName = 0x45a3L;
//! ID of the tag content.
const ulli TagString = 0x4487L;
//! The DocType of a matroska file.
const String DocTypeMatroska = "matroska";
//! The DocType of a WebM file.
const String DocTypeWebM = "webm";
//! The TITLE entry
const String TITLE = "TITLE";
//! The ARTIST entry
const String ARTIST = "ARTIST";
//! The COMMENT entry
const String COMMENT = "COMMENT";
//! The GENRE entry
const String GENRE = "GENRE";
//! The DATE_RELEASE entry
const String DATE_RELEASE = "DATE_RELEASE";
//! The PART_NUMBER entry
const String PART_NUMBER = "PART_NUMBER";
//! The TargetTypeValue of the most common grouping level (e.g. album)
const ulli MostCommonGroupingValue = 50;
//! The TargetTypeValue of the most common parts of a group (e.g. track)
const ulli MostCommonPartValue = 30;
//! Name of the TargetType of an album.
const String ALBUM = "ALBUM";
//! Name of the TargetType of a track.
const String TRACK = "TRACK";
// For AudioProperties
//! ID of the Info block within the Segment.
const ulli SegmentInfo = 0x1549a966L;
//! ID of the duration element.
const ulli Duration = 0x4489L;
//! ID of TimecodeScale element.
const ulli TimecodeScale = 0x2ad7b1L;
//! ID of the Tracks container
const ulli Tracks = 0x1654ae6bL;
//! ID of a TrackEntry element.
const ulli TrackEntry = 0xaeL;
//! ID of the Audio container.
const ulli Audio = 0xe1L;
//! ID of the SamplingFrequency element.
const ulli SamplingFrequency = 0xb5L;
//! ID of the Channels element.
const ulli Channels = 0x9fL;
//! ID of the BitDepth element.
const ulli BitDepth = 0x6264L;
}
}
}
}
#endif

View File

@@ -0,0 +1,563 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "ebmlmatroskaconstants.h"
#include "ebmlmatroskaaudio.h"
#include "tpicturemap.h"
#include "tpropertymap.h"
using namespace TagLib;
class EBML::Matroska::File::FilePrivate
{
public:
// Returns true if simpleTag has a TagName and TagString child and writes
// their contents into name and value.
bool extractContent(Element *simpleTag, String &name, String &value)
{
Element *n = simpleTag->getChild(Constants::TagName);
Element *v = simpleTag->getChild(Constants::TagString);
if(!n || !v)
return false;
name = n->getAsString();
value = v->getAsString();
return true;
}
explicit FilePrivate(File *p_document) : tag(0), document(p_document)
{
// Just get the first segment, because "Typically a Matroska file is
// composed of 1 segment."
Element* elem = document->getDocumentRoot()->getChild(Constants::Segment);
// We take the first tags element (there shouldn't be more), if there is
// non such element, consider the file as not compatible.
if(!elem || !(elem = elem->getChild(Constants::Tags))) {
document->setValid(false);
return;
}
// Load all Tag entries
List<Element *> entries = elem->getChildren(Constants::Tag);
for(List<Element *>::Iterator i = entries.begin(); i != entries.end(); ++i) {
Element *target = (*i)->getChild(Constants::Targets);
ulli ttvalue = 50; // 50 is default (see spec.)
if(target && (target = target->getChild(Constants::TargetTypeValue)))
ttvalue = target->getAsUnsigned();
// Load all SimpleTags
PropertyMap tagEntries;
List<Element *> simpleTags = (*i)->getChildren(Constants::SimpleTag);
for(List<Element *>::Iterator j = simpleTags.begin(); j != simpleTags.end();
++j) {
String name, value;
if(!extractContent(*j, name, value))
continue;
tagEntries.insert(name, StringList(value));
}
tags.append(std::pair<PropertyMap, std::pair<Element *, ulli> >(tagEntries, std::pair<Element *, ulli>(*i, ttvalue)));
}
}
// Creates Tag and AudioProperties. Late creation because both require a fully
// functional FilePrivate (well AudioProperties doesn't...)
void lateCreate()
{
tag = new Tag(document);
audio = new AudioProperties(document);
}
// Checks the EBML header and creates the FilePrivate.
static FilePrivate *checkAndCreate(File *document)
{
Element *elem = document->getDocumentRoot()->getChild(Header::EBML);
Element *child = elem->getChild(Header::DocType);
if(child) {
String dt = child->getAsString();
if (dt == Constants::DocTypeMatroska || dt == Constants::DocTypeWebM) {
FilePrivate *fp = new FilePrivate(document);
return fp;
}
}
return 0;
}
// The tags with their Element and TargetTypeValue
List<std::pair<PropertyMap, std::pair<Element *, ulli> > > tags;
// The tag
Tag *tag;
// The audio properties
AudioProperties *audio;
// The corresponding file.
File *document;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
EBML::Matroska::File::~File()
{
if (d) {
delete d->tag;
delete d->audio;
delete d;
}
}
EBML::Matroska::File::File(FileName file, bool, AudioProperties::ReadStyle) : EBML::File(file), d(0)
{
if(isValid() && isOpen()) {
d = FilePrivate::checkAndCreate(this);
if(!d)
setValid(false);
else
d->lateCreate();
}
}
EBML::Matroska::File::File(IOStream *stream, bool, AudioProperties::ReadStyle) : EBML::File(stream), d(0)
{
if(isValid() && isOpen()) {
d = FilePrivate::checkAndCreate(this);
if(!d)
setValid(false);
else
d->lateCreate();
}
}
Tag *EBML::Matroska::File::tag() const
{
return d->tag;
}
PropertyMap EBML::Matroska::File::properties() const
{
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator best = d->tags.end();
for(List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator i = d->tags.begin();
i != d->tags.end(); ++i) {
if(best == d->tags.end() || best->second.second > i->second.second)
best = i;
}
return best->first;
}
PropertyMap EBML::Matroska::File::setProperties(const PropertyMap &properties)
{
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator best = d->tags.end();
for(List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator i = d->tags.begin();
i != d->tags.end(); ++i) {
if(best == d->tags.end() || best->second.second > i->second.second)
best = i;
}
std::pair<PropertyMap, std::pair<Element *, ulli> > replace(properties, best->second);
d->tags.erase(best);
d->tags.prepend(replace);
return PropertyMap();
}
AudioProperties *EBML::Matroska::File::audioProperties() const
{
return d->audio;
}
bool EBML::Matroska::File::save()
{
if(readOnly())
return false;
// C++11 features would be nice: for(auto &i : d->tags) { /* ... */ }
// Well, here we just iterate each extracted element.
for(List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator i = d->tags.begin();
i != d->tags.end(); ++i) {
for(PropertyMap::Iterator j = i->first.begin(); j != i->first.end(); ++j) {
// No element? Create it!
if(!i->second.first) {
// Should be save, since we already checked, when creating the object.
Element *container = d->document->getDocumentRoot()
->getChild(Constants::Segment)->getChild(Constants::Tags);
// Create Targets container
i->second.first = container->addElement(Constants::Tag);
Element *target = i->second.first->addElement(Constants::Targets);
if(i->second.second == Constants::MostCommonPartValue)
target->addElement(Constants::TargetType, Constants::TRACK);
else if(i->second.second == Constants::MostCommonGroupingValue)
target->addElement(Constants::TargetType, Constants::ALBUM);
target->addElement(Constants::TargetTypeValue, i->second.second);
}
// Find entries
List<Element *> simpleTags = i->second.first->getChildren(Constants::SimpleTag);
StringList::Iterator str = j->second.begin();
List<Element *>::Iterator k = simpleTags.begin();
for(; k != simpleTags.end(); ++k) {
String name, value;
if(!d->extractContent(*k, name, value))
continue;
// Write entry from StringList
if(name == j->first) {
if(str == j->second.end()) {
// We have all StringList elements but still found another element
// with the same name? Let's delete it!
i->second.first->removeChild(*k);
}
else {
if(value != *str) {
// extractContent already checked for availability
(*k)->getChild(Constants::TagString)->setAsString(*str);
}
++str;
}
}
}
// If we didn't write the complete StringList, we have to write the rest.
for(; str != j->second.end(); ++str) {
Element *stag = i->second.first->addElement(Constants::SimpleTag);
stag->addElement(Constants::TagName, j->first);
stag->addElement(Constants::TagString, *str);
}
}
// Finally, we have to find elements that are not in the PropertyMap and
// remove them.
List<Element *> simpleTags = i->second.first->getChildren(Constants::SimpleTag);
for(List<Element *>::Iterator j = simpleTags.begin(); j != simpleTags.end(); ++j) {
String name, value;
if(!d->extractContent(*j, name, value))
continue;
if(i->first.find(name) == i->first.end()){
i->second.first->removeChild(*j);}
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
//
// Tag
//
////////////////////////////////////////////////////////////////////////////////
class EBML::Matroska::File::Tag::TagPrivate
{
public:
// Creates a TagPrivate instance
explicit TagPrivate(File *p_document) :
document(p_document),
title(document->d->tags.end()),
artist(document->d->tags.end()),
album(document->d->tags.end()),
comment(document->d->tags.end()),
genre(document->d->tags.end()),
year(document->d->tags.end()),
track(document->d->tags.end())
{
for(List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator i =
document->d->tags.begin(); i != document->d->tags.end(); ++i) {
// Just save it, if the title is more specific, or there is no title yet.
if(i->first.find(Constants::TITLE) != i->first.end() &&
(title == document->d->tags.end() ||
title->second.second > i->second.second ||
i->second.second == Constants::MostCommonPartValue)) {
title = i;
}
// Same goes for artist.
if(i->first.find(Constants::ARTIST) != i->first.end() &&
(artist == document->d->tags.end() ||
artist->second.second > i->second.second ||
i->second.second == Constants::MostCommonPartValue)) {
artist = i;
}
// Here, we also look for a title (the album title), but since we
// specified the granularity, we have to search for it exactly.
// Therefore it is possible, that title and album are the same (if only
// the title of the album is given).
if(i->first.find(Constants::TITLE) != i->first.end() &&
i->second.second == Constants::MostCommonGroupingValue) {
album = i;
}
// Again the same as title and artist.
if(i->first.find(Constants::COMMENT) != i->first.end() &&
(comment == document->d->tags.end() ||
comment->second.second > i->second.second ||
i->second.second == Constants::MostCommonPartValue)) {
comment = i;
}
// Same goes for genre.
if(i->first.find(Constants::GENRE) != i->first.end() &&
(genre == document->d->tags.end() ||
genre->second.second > i->second.second ||
i->second.second == Constants::MostCommonPartValue)) {
genre = i;
}
// And year (in our case: DATE_REALEASE)
if(i->first.find(Constants::DATE_RELEASE) != i->first.end() &&
(year == document->d->tags.end() ||
year->second.second > i->second.second ||
i->second.second == Constants::MostCommonPartValue)) {
year = i;
}
// And track (in our case: PART_NUMBER)
if(i->first.find(Constants::PART_NUMBER) != i->first.end() &&
(track == document->d->tags.end() ||
track->second.second > i->second.second ||
i->second.second == Constants::MostCommonPartValue)) {
track = i;
}
}
}
// Searches for the Tag with given TargetTypeValue (returns the first one)
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator
find(ulli ttv)
{
for(List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator i =
document->d->tags.begin(); i != document->d->tags.end(); ++i) {
if(i->second.second == ttv)
return i;
}
return document->d->tags.end();
}
// Updates the given information
void update(
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator t,
const String &tagname,
const String &s
)
{
t->first.find(tagname)->second.front() = s;
}
// Inserts a tag with given information
void insert(const String &tagname, const ulli ttv, const String &s)
{
for(List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator i =
document->d->tags.begin(); i != document->d->tags.end(); ++i) {
if(i->second.second == ttv) {
i->first.insert(tagname, StringList(s));
return;
}
}
// Not found? Create new!
PropertyMap pm;
pm.insert(tagname, StringList(s));
document->d->tags.append(
std::pair<PropertyMap, std::pair<Element *, ulli> >(pm,
std::pair<Element *, ulli>(static_cast<Element *>(0), ttv)
)
);
}
// The PropertyMap from the Matroska::File
File *document;
// Iterators to the tags.
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator title;
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator artist;
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator album;
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator comment;
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator genre;
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator year;
List<std::pair<PropertyMap, std::pair<Element *, ulli> > >::Iterator track;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
EBML::Matroska::File::Tag::~Tag()
{
delete e;
}
EBML::Matroska::File::Tag::Tag(EBML::Matroska::File *document) :
e(new EBML::Matroska::File::Tag::TagPrivate(document))
{
}
String EBML::Matroska::File::Tag::title() const
{
if(e->title != e->document->d->tags.end())
return e->title->first.find(Constants::TITLE)->second.front();
else
return String();
}
String EBML::Matroska::File::Tag::artist() const
{
if(e->artist != e->document->d->tags.end())
return e->artist->first.find(Constants::ARTIST)->second.front();
else
return String();
}
String EBML::Matroska::File::Tag::album() const
{
if(e->album != e->document->d->tags.end())
return e->album->first.find(Constants::TITLE)->second.front();
else
return String();
}
PictureMap EBML::Matroska::File::Tag::pictures() const
{
return PictureMap();
}
String EBML::Matroska::File::Tag::comment() const
{
if(e->comment != e->document->d->tags.end())
return e->comment->first.find(Constants::COMMENT)->second.front();
else
return String();
}
String EBML::Matroska::File::Tag::genre() const
{
if(e->genre != e->document->d->tags.end())
return e->genre->first.find(Constants::GENRE)->second.front();
else
return String();
}
unsigned int EBML::Matroska::File::Tag::year() const
{
if(e->year != e->document->d->tags.end())
return e->year->first.find(Constants::DATE_RELEASE)->second.front().toInt();
else
return 0;
}
unsigned int EBML::Matroska::File::Tag::track() const
{
if(e->track != e->document->d->tags.end())
return e->track->first.find(Constants::PART_NUMBER)->second.front().toInt();
else
return 0;
}
void EBML::Matroska::File::Tag::setTitle(const String &s)
{
if(e->title != e->document->d->tags.end())
e->update(e->title, Constants::TITLE, s);
else
e->insert(Constants::TITLE, Constants::MostCommonPartValue, s);
}
void EBML::Matroska::File::Tag::setArtist(const String &s)
{
if(e->artist != e->document->d->tags.end())
e->update(e->artist, Constants::ARTIST, s);
else
e->insert(Constants::ARTIST, Constants::MostCommonPartValue, s);
}
void EBML::Matroska::File::Tag::setAlbum(const String &s)
{
if(e->album != e->document->d->tags.end())
e->update(e->album, Constants::TITLE, s);
else
e->insert(Constants::TITLE, Constants::MostCommonGroupingValue, s);
}
void EBML::Matroska::File::Tag::setPictures(const PictureMap& p )
{
(void)p; // avoid warning for unused variable
}
void EBML::Matroska::File::Tag::setComment(const String &s)
{
if(e->comment != e->document->d->tags.end())
e->update(e->comment, Constants::COMMENT, s);
else
e->insert(Constants::COMMENT, Constants::MostCommonPartValue, s);
}
void EBML::Matroska::File::Tag::setGenre(const String &s)
{
if(e->genre != e->document->d->tags.end())
e->update(e->genre, Constants::GENRE, s);
else
e->insert(Constants::GENRE, Constants::MostCommonPartValue, s);
}
void EBML::Matroska::File::Tag::setYear(unsigned int i)
{
String s = String::number(i);
if(e->year != e->document->d->tags.end())
e->update(e->year, Constants::DATE_RELEASE, s);
else
e->insert(Constants::DATE_RELEASE, Constants::MostCommonPartValue, s);
}
void EBML::Matroska::File::Tag::setTrack(unsigned int i)
{
String s = String::number(i);
if(e->track != e->document->d->tags.end())
e->update(e->track, Constants::PART_NUMBER, s);
else
e->insert(Constants::PART_NUMBER, Constants::MostCommonPartValue, s);
}

View File

@@ -0,0 +1,228 @@
/***************************************************************************
copyright : (C) 2013 by Sebastian Rachuj
email : rachus@web.de
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_EBMLMATROSKAFILE_H
#define TAGLIB_EBMLMATROSKAFILE_H
#include "ebmlelement.h"
#include "audioproperties.h"
namespace TagLib {
namespace EBML {
//! Implementation for reading Matroska tags.
namespace Matroska {
/*!
* Implements the TagLib::File API and offers access to the tags of the
* matroska file.
*/
class TAGLIB_EXPORT File : public EBML::File
{
public:
//! Destroys the instance of the file.
virtual ~File();
/*!
* Constructs a Matroska file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
* read.
*/
explicit File(FileName file, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Constructs a Matroska file from \a stream. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
* read.
*/
explicit File(IOStream *stream, bool readproperties = true,
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Returns the pointer to a tag that allow access on common tags.
*/
virtual TagLib::Tag *tag() const;
/*!
* Exports the tags to a PropertyMap. Due to the diversity of the
* Matroska format (e.g. multiple media streams in one file, each with
* its own tags), only the best fitting tags are taken into account.
* There are no unsupported tags.
*/
virtual PropertyMap properties() const;
/*!
* Sets the tags of the file to those specified in properties. The
* returned PropertyMap is always empty.
* Note: Only the best fitting tags are taken into account.
*/
virtual PropertyMap setProperties(const PropertyMap &properties);
/*!
* Returns a pointer to this file's audio properties.
*
* I'm glad about not having a setAudioProperties method ;)
*/
virtual AudioProperties *audioProperties() const;
/*!
* Saves the file. Returns true on success.
*/
bool save();
/*!
* Offers access to a few common tag entries.
*/
class Tag : public TagLib::Tag
{
public:
//! Destroys the tag.
~Tag();
/*!
* Creates a new Tag for Matroska files. The given properties are gained
* by the Matroska::File.
*/
explicit Tag(File *document);
/*!
* Returns the track name; if no track name is present in the tag
* String::null will be returned.
*/
virtual String title() const;
/*!
* Returns the artist name; if no artist name is present in the tag
* String::null will be returned.
*/
virtual String artist() const;
/*!
* Returns the album name; if no album name is present in the tag
* String::null will be returned.
*/
virtual String album() const;
/*!
* Returns a list of pictures; if no picture is present in the tag
* an empty PictureMap is returned
*/
virtual PictureMap pictures() const;
/*!
* Returns the track comment; if no comment is present in the tag
* String::null will be returned.
*/
virtual String comment() const;
/*!
* Returns the genre name; if no genre is present in the tag String::null
* will be returned.
*/
virtual String genre() const;
/*!
* Returns the year; if there is no year set, this will return 0.
*/
virtual unsigned int year() const;
/*!
* Returns the track number; if there is no track number set, this will
* return 0.
*/
virtual unsigned int track() const;
/*!
* Sets the title to s. If s is String::null then this value will be
* cleared.
*/
virtual void setTitle(const String &s);
/*!
* Sets the artist to s. If s is String::null then this value will be
* cleared.
*/
virtual void setArtist(const String &s);
/*!
* Sets the album to s. If s is String::null then this value will be
* cleared.
*/
virtual void setAlbum(const String &s);
/*!
* Sets the picture map to p. If p is empty then this value will be
* cleared
*/
virtual void setPictures(const PictureMap& p );
/*!
* Sets the comment to s. If s is String::null then this value will be
* cleared.
*/
virtual void setComment(const String &s);
/*!
* Sets the genre to s. If s is String::null then this value will be
* cleared.
*/
virtual void setGenre(const String &s);
/*!
* Sets the year to i. If s is 0 then this value will be cleared.
*/
virtual void setYear(unsigned int i);
/*!
* Sets the track to i. If s is 0 then this value will be cleared.
*/
virtual void setTrack(unsigned int i);
private:
class TagPrivate;
TagPrivate *e;
};
private:
class FilePrivate;
FilePrivate *d;
};
}
}
}
#endif

View File

@@ -27,84 +27,55 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tfile.h>
#include <tfilestream.h>
#include <tstring.h>
#include <tdebug.h>
#include <tsmartptr.h>
#include "fileref.h"
#include <cstring>
#include <utility>
#include "tfilestream.h"
#include "tpropertymap.h"
#include "tstringlist.h"
#include "tvariant.h"
#include "tdebug.h"
#include "aifffile.h"
#include "apefile.h"
#include "asffile.h"
#include "flacfile.h"
#include "itfile.h"
#include "modfile.h"
#include "mp4file.h"
#include "mpcfile.h"
#include "mpegfile.h"
#include "oggflacfile.h"
#include "opusfile.h"
#include "s3mfile.h"
#include "speexfile.h"
#include "trueaudiofile.h"
#include "vorbisfile.h"
#include "wavfile.h"
#include "flacfile.h"
#include "oggflacfile.h"
#include "mpcfile.h"
#include "mp4file.h"
#include "wavpackfile.h"
#include "speexfile.h"
#include "opusfile.h"
#include "trueaudiofile.h"
#include "aifffile.h"
#include "wavfile.h"
#include "apefile.h"
#include "modfile.h"
#include "s3mfile.h"
#include "itfile.h"
#include "xmfile.h"
#include "dsffile.h"
#include "dsdifffile.h"
#include "ebmlmatroskafile.h"
using namespace TagLib;
class FileRef::FileTypeResolver::FileTypeResolverPrivate
{
};
class FileRef::StreamTypeResolver::StreamTypeResolverPrivate
{
};
namespace
{
List<const FileRef::FileTypeResolver *> fileTypeResolvers;
typedef List<const FileRef::FileTypeResolver *> ResolverList;
ResolverList fileTypeResolvers;
// Detect the file type by user-defined resolvers.
File *detectByResolvers(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
#ifdef _WIN32
if(::wcslen(fileName) == 0)
return nullptr;
#else
if(::strlen(fileName) == 0)
return nullptr;
#endif
for(const auto &resolver : std::as_const(fileTypeResolvers)) {
File *file = resolver->createFile(fileName, readAudioProperties, audioPropertiesStyle);
ResolverList::ConstIterator it = fileTypeResolvers.begin();
for(; it != fileTypeResolvers.end(); ++it) {
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
if(file)
return file;
}
return nullptr;
}
File *detectByResolvers(IOStream* stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
for(const auto &resolver : std::as_const(fileTypeResolvers)) {
if(auto streamResolver = dynamic_cast<const FileRef::StreamTypeResolver *>(resolver)) {
if(File *file = streamResolver->createFileFromStream(
stream, readAudioProperties, audioPropertiesStyle))
return file;
}
}
return nullptr;
return 0;
}
// Detect the file type based on the file extension.
@@ -113,14 +84,14 @@ namespace
AudioProperties::ReadStyle audioPropertiesStyle)
{
#ifdef _WIN32
const String s = stream->name().toString();
const String s(stream->name().wstr());
#else
const String s(stream->name());
#endif
String ext;
const int pos = s.rfind(".");
if(pos != -1)
const size_t pos = s.rfind(".");
if(pos != String::npos())
ext = s.substr(pos + 1).upper();
// If this list is updated, the method defaultFileExtensions() should also be
@@ -128,69 +99,54 @@ namespace
// that a default file type resolver is created.
if(ext.isEmpty())
return nullptr;
return 0;
// .oga can be any audio in the Ogg container. So leave it to content-based detection.
File *file = nullptr;
if(ext == "MP3" || ext == "MP2" || ext == "AAC")
file = new MPEG::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "OGG")
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "OGA") {
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
if(!file->isValid()) {
delete file;
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
}
}
else if(ext == "FLAC")
file = new FLAC::File(stream, 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);
if(ext == "MP3")
return new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "OGG")
return new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "FLAC")
return new FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "MPC")
return new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "WV")
return new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "SPX")
return new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "OPUS")
return new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "TTA")
return new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
return new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
return new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "APE")
return 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);
else if(ext == "DSF")
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "DFF" || ext == "DSDIFF")
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
// if file is not valid, leave it to content-based detection.
if(file) {
if(file->isValid())
return file;
delete file;
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
return new Mod::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "S3M")
return new S3M::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "IT")
return new IT::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "DFF" || ext == "DSDIFF")
return new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "DSF")
return new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
if (ext == "MKA" || ext == "MKV") {
return new EBML::Matroska::File(stream, readAudioProperties, audioPropertiesStyle);
}
return nullptr;
return 0;
}
// Detect the file type based on the actual content of the stream.
@@ -198,10 +154,10 @@ namespace
File *detectByContent(IOStream *stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
File *file = nullptr;
File *file = 0;
if(MPEG::File::isSupported(stream))
file = new MPEG::File(stream, readAudioProperties, audioPropertiesStyle);
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))
@@ -228,53 +184,46 @@ namespace
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSF::File::isSupported(stream))
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSDIFF::File::isSupported(stream))
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSF::File::isSupported(stream))
file = new DSF::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;
else
delete file;
}
return nullptr;
return 0;
}
} // namespace
struct FileRefData
{
FileRefData() :
file(0),
stream(0) {}
~FileRefData() {
delete file;
delete stream;
}
File *file;
IOStream *stream;
};
}
class FileRef::FileRefPrivate
{
public:
FileRefPrivate() = default;
~FileRefPrivate()
{
delete file;
delete stream;
}
FileRefPrivate() :
data(new FileRefData()) {}
FileRefPrivate(const FileRefPrivate &) = delete;
FileRefPrivate &operator=(const FileRefPrivate &) = delete;
bool isNull() const
{
return !file || !file->isValid();
}
bool isNullWithDebugMessage(const String &methodName) const
{
if(isNull()) {
debug("FileRef::" + methodName + "() - Called without a valid file.");
return true;
}
return false;
}
File *file { nullptr };
IOStream *stream { nullptr };
SHARED_PTR<FileRefData> data;
};
////////////////////////////////////////////////////////////////////////////////
@@ -282,108 +231,99 @@ public:
////////////////////////////////////////////////////////////////////////////////
FileRef::FileRef() :
d(std::make_shared<FileRefPrivate>())
d(new FileRefPrivate())
{
}
FileRef::FileRef(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle) :
d(std::make_shared<FileRefPrivate>())
d(new FileRefPrivate())
{
parse(fileName, readAudioProperties, audioPropertiesStyle);
}
FileRef::FileRef(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) :
d(std::make_shared<FileRefPrivate>())
FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) :
d(new FileRefPrivate())
{
parse(stream, readAudioProperties, audioPropertiesStyle);
}
FileRef::FileRef(File *file) :
d(std::make_shared<FileRefPrivate>())
d(new FileRefPrivate())
{
d->file = file;
d->data->file = file;
}
FileRef::FileRef(const FileRef &) = default;
FileRef::FileRef(const FileRef &ref) :
d(new FileRefPrivate(*ref.d))
{
}
FileRef::~FileRef() = default;
FileRef::~FileRef()
{
delete d;
}
Tag *FileRef::tag() const
{
if(d->isNullWithDebugMessage(__func__)) {
return nullptr;
if(isNull()) {
debug("FileRef::tag() - Called without a valid file.");
return 0;
}
return d->file->tag();
return d->data->file->tag();
}
PropertyMap FileRef::properties() const
{
if(d->isNullWithDebugMessage(__func__)) {
if(isNull()) {
debug("FileRef::properties() - Called without a valid file.");
return PropertyMap();
}
return d->file->properties();
return d->data->file->properties();
}
void FileRef::removeUnsupportedProperties(const StringList& properties)
{
if(d->isNullWithDebugMessage(__func__)) {
if(isNull()) {
debug("FileRef::removeUnsupportedProperties() - Called without a valid file.");
return;
}
return d->file->removeUnsupportedProperties(properties);
d->data->file->removeUnsupportedProperties(properties);
}
PropertyMap FileRef::setProperties(const PropertyMap &properties)
{
if(d->isNullWithDebugMessage(__func__)) {
if(isNull()) {
debug("FileRef::setProperties() - Called without a valid file.");
return PropertyMap();
}
return d->file->setProperties(properties);
}
StringList FileRef::complexPropertyKeys() const
{
if(d->isNullWithDebugMessage(__func__)) {
return StringList();
}
return d->file->complexPropertyKeys();
}
List<VariantMap> FileRef::complexProperties(const String &key) const
{
if(d->isNullWithDebugMessage(__func__)) {
return List<VariantMap>();
}
return d->file->complexProperties(key);
}
bool FileRef::setComplexProperties(const String &key, const List<VariantMap> &value)
{
if(d->isNullWithDebugMessage(__func__)) {
return false;
}
return d->file->setComplexProperties(key, value);
return d->data->file->setProperties(properties);
}
AudioProperties *FileRef::audioProperties() const
{
if(d->isNullWithDebugMessage(__func__)) {
return nullptr;
if(isNull()) {
debug("FileRef::audioProperties() - Called without a valid file.");
return 0;
}
return d->file->audioProperties();
return d->data->file->audioProperties();
}
File *FileRef::file() const
{
return d->file;
return d->data->file;
}
bool FileRef::save()
{
if(d->isNullWithDebugMessage(__func__)) {
if(isNull()) {
debug("FileRef::save() - Called without a valid file.");
return false;
}
return d->file->save();
return d->data->file->save();
}
const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static
@@ -392,11 +332,6 @@ const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::Fil
return resolver;
}
void FileRef::clearFileTypeResolvers() // static
{
fileTypeResolvers.clear();
}
StringList FileRef::defaultFileExtensions()
{
StringList l;
@@ -404,14 +339,11 @@ StringList FileRef::defaultFileExtensions()
l.append("ogg");
l.append("flac");
l.append("oga");
l.append("opus");
l.append("mp3");
l.append("mp2");
l.append("mpc");
l.append("wv");
l.append("spx");
l.append("tta");
l.append("aac");
l.append("m4a");
l.append("m4r");
l.append("m4b");
@@ -423,8 +355,6 @@ 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");
@@ -437,18 +367,29 @@ StringList FileRef::defaultFileExtensions()
l.append("dsf");
l.append("dff");
l.append("dsdiff"); // alias for "dff"
l.append("mka");
l.append("mkv");
return l;
}
bool FileRef::isNull() const
bool FileRef::isValid() const
{
return d->isNull();
return (d->data->file && d->data->file->isValid());
}
FileRef &FileRef::operator=(const FileRef &) = default;
bool FileRef::isNull() const
{
return !isValid();
}
void FileRef::swap(FileRef &ref) noexcept
FileRef &FileRef::operator=(const FileRef &ref)
{
FileRef(ref).swap(*this);
return *this;
}
void FileRef::swap(FileRef &ref)
{
using std::swap;
@@ -457,12 +398,12 @@ void FileRef::swap(FileRef &ref) noexcept
bool FileRef::operator==(const FileRef &ref) const
{
return (ref.d->file == d->file);
return (ref.d->data == d->data);
}
bool FileRef::operator!=(const FileRef &ref) const
{
return (ref.d->file != d->file);
return (ref.d->data != d->data);
}
////////////////////////////////////////////////////////////////////////////////
@@ -474,57 +415,41 @@ void FileRef::parse(FileName fileName, bool readAudioProperties,
{
// Try user-defined resolvers.
d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
if(d->file)
d->data->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
if(d->data->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)
d->data->stream = new FileStream(fileName);
d->data->file = detectByExtension(d->data->stream, readAudioProperties, audioPropertiesStyle);
if(d->data->file)
return;
// At last, try to resolve file types based on the actual content.
d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
d->data->file = detectByContent(d->data->stream, readAudioProperties, audioPropertiesStyle);
if(d->data->file)
return;
// Stream have to be closed here if failed to resolve file types.
delete d->stream;
d->stream = nullptr;
delete d->data->stream;
d->data->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;
// User-defined resolvers won't work with a stream.
// Try to resolve file types based on the file extension.
d->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
d->data->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle);
if(d->data->file)
return;
// At last, try to resolve file types based on the actual content of the file.
d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
d->data->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
}
FileRef::FileTypeResolver::FileTypeResolver() = default;
FileRef::FileTypeResolver::~FileTypeResolver() = default;
FileRef::StreamTypeResolver::StreamTypeResolver() = default;
FileRef::StreamTypeResolver::~StreamTypeResolver() = default;

View File

@@ -26,10 +26,10 @@
#ifndef TAGLIB_FILEREF_H
#define TAGLIB_FILEREF_H
#include "taglib_export.h"
#include "tfile.h"
#include "tstringlist.h"
#include "taglib_export.h"
#include "tpropertymap.h"
#include "audioproperties.h"
namespace TagLib {
@@ -63,7 +63,7 @@ namespace TagLib {
//! A class for pluggable file type resolution.
/*!
* This class is used to extend TagLib's very basic file name based file
* This class is used to add extend TagLib's very basic file name based file
* type resolution.
*
* This can be accomplished with:
@@ -92,19 +92,12 @@ namespace TagLib {
class TAGLIB_EXPORT FileTypeResolver
{
public:
FileTypeResolver();
/*!
* Destroys this FileTypeResolver instance.
*/
virtual ~FileTypeResolver() = 0;
FileTypeResolver(const FileTypeResolver &) = delete;
FileTypeResolver &operator=(const FileTypeResolver &) = delete;
virtual ~FileTypeResolver() {}
/*!
* This method must be overridden to provide an additional file type
* resolver. If the resolver is able to determine the file type it should
* return a valid File object; if not it should return nullptr.
* return a valid File object; if not it should return 0.
*
* \note The created file is then owned by the FileRef and should not be
* deleted. Deletion will happen automatically when the FileRef passes
@@ -114,32 +107,6 @@ namespace TagLib {
bool readAudioProperties = true,
AudioProperties::ReadStyle
audioPropertiesStyle = AudioProperties::Average) const = 0;
private:
class FileTypeResolverPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FileTypeResolverPrivate> d;
};
class TAGLIB_EXPORT StreamTypeResolver : public FileTypeResolver
{
public:
StreamTypeResolver();
/*!
* Destroys this StreamTypeResolver instance.
*/
~StreamTypeResolver() override = 0;
StreamTypeResolver(const StreamTypeResolver &) = delete;
StreamTypeResolver &operator=(const StreamTypeResolver &) = delete;
virtual File *createFileFromStream(IOStream *stream,
bool readAudioProperties = true,
AudioProperties::ReadStyle
audioPropertiesStyle = AudioProperties::Average) const = 0;
private:
class StreamTypeResolverPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<StreamTypeResolverPrivate> d;
};
/*!
@@ -192,7 +159,7 @@ namespace TagLib {
/*!
* Destroys this FileRef instance.
*/
~FileRef();
virtual ~FileRef();
/*!
* Returns a pointer to represented file's tag.
@@ -200,8 +167,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 Tag.
* Use tag returning methods of appropriate subclasses of File instead.
* \warning Do not cast it to any subclasses of \class Tag.
* Use tag returning methods of appropriate subclasses of \class File instead.
*
* \see File::tag()
*/
@@ -209,10 +176,10 @@ namespace TagLib {
/*!
* Exports the tags of the file as dictionary mapping (human readable) tag
* names (uppercase Strings) to StringLists of tag values. Calls this
* method on the wrapped File instance.
* names (uppercase Strings) to StringLists of tag values. Calls the according
* specialization in the File subclasses.
* For each metadata object of the file that could not be parsed into the PropertyMap
* format, the returned map's unsupportedData() list will contain one entry identifying
* format, the returend map's unsupportedData() list will contain one entry identifying
* that object (e.g. the frame type for ID3v2 tags). Use removeUnsupportedProperties()
* to remove (a subset of) them.
* For files that contain more than one tag (e.g. an MP3 with both an ID3v1 and an ID3v2
@@ -228,10 +195,12 @@ namespace TagLib {
void removeUnsupportedProperties(const StringList& properties);
/*!
* Sets the tags of the wrapped File to those specified in \a properties.
* If some value(s) could not be written to the specific metadata format,
* Sets the tags of this File to those specified in \a properties. Calls the
* according specialization method in the subclasses of File to do the translation
* into the format-specific details.
* If some value(s) could not be written imported to the specific metadata format,
* the returned PropertyMap will contain those value(s). Otherwise it will be empty,
* indicating that no problems occurred.
* indicating that no problems occured.
* With file types that support several tag formats (for instance, MP3 files can have
* ID3v1, ID3v2, and APEv2 tags), this function will create the most appropriate one
* (ID3v2 for MP3 files). Older formats will be updated as well, if they exist, but won't
@@ -240,51 +209,6 @@ namespace TagLib {
*/
PropertyMap setProperties(const PropertyMap &properties);
/*!
* Get the keys of complex properties, i.e. properties which cannot be
* represented simply by a string.
* Because such properties might be expensive to fetch, there are separate
* operations to get the available keys - which is expected to be cheap -
* and getting and setting the property values.
* Calls the method on the wrapped File, which collects the keys from one
* or more of its tags.
*/
StringList complexPropertyKeys() const;
/*!
* Get the complex properties for a given \a key.
* In order to be flexible for different metadata formats, the properties
* are represented as variant maps. Despite this dynamic nature, some
* degree of standardization should be achieved between formats:
*
* - PICTURE
* - data: ByteVector with picture data
* - description: String with description
* - pictureType: String with type as specified for ID3v2,
* e.g. "Front Cover", "Back Cover", "Band"
* - mimeType: String with image format, e.g. "image/jpeg"
* - optionally more information found in the tag, such as
* "width", "height", "numColors", "colorDepth" int values
* in FLAC pictures
* - GENERALOBJECT
* - data: ByteVector with object data
* - description: String with description
* - fileName: String with file name
* - mimeType: String with MIME type
* - this is currently only implemented for ID3v2 GEOB frames
*
* Calls the method on the wrapped File, which gets the properties from one
* or more of its tags.
*/
List<VariantMap> complexProperties(const String &key) const;
/*!
* Set all complex properties for a given \a key using variant maps as
* \a value with the same format as returned by complexProperties().
* An empty list as \a value removes all complex properties for \a key.
*/
bool setComplexProperties(const String &key, const List<VariantMap> &value);
/*!
* Returns the audio properties for this FileRef. If no audio properties
* were read then this will returns a null pointer.
@@ -327,11 +251,6 @@ namespace TagLib {
*/
static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver);
/*!
* Remove all resolvers added by addFileTypeResolver().
*/
static void clearFileTypeResolvers();
/*!
* As is mentioned elsewhere in this class's documentation, the default file
* type resolution code provided by TagLib only works by comparing file
@@ -350,8 +269,17 @@ namespace TagLib {
*/
static StringList defaultFileExtensions();
/*!
* Returns true if the file is open and readable.
*
* \note Just a negative of isNull().
*/
bool isValid() const;
/*!
* Returns true if the file (and as such other pointers) are null.
*
* \note Just a negative of isValid().
*/
bool isNull() const;
@@ -363,7 +291,7 @@ namespace TagLib {
/*!
* Exchanges the content of the FileRef by the content of \a ref.
*/
void swap(FileRef &ref) noexcept;
void swap(FileRef &ref);
/*!
* Returns true if this FileRef and \a ref point to the same File object.
@@ -381,8 +309,7 @@ namespace TagLib {
void parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
class FileRefPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::shared_ptr<FileRefPrivate> d;
FileRefPrivate *d;
};
} // namespace TagLib

View File

@@ -23,19 +23,22 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "flacfile.h"
#include <tbytevector.h>
#include <tstring.h>
#include <tlist.h>
#include <tdebug.h>
#include <tagunion.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include <tsmartptr.h>
#include <algorithm>
#include <utility>
#include <id3v2header.h>
#include <id3v2tag.h>
#include <id3v1tag.h>
#include <xiphcomment.h>
#include "tdebug.h"
#include "tpropertymap.h"
#include "tagunion.h"
#include "tagutils.h"
#include "id3v2tag.h"
#include "id3v1tag.h"
#include "xiphcomment.h"
#include "flacpicture.h"
#include "flacfile.h"
#include "flacmetadatablock.h"
#include "flacunknownmetadatablock.h"
@@ -43,38 +46,62 @@ using namespace TagLib;
namespace
{
typedef List<SHARED_PTR<FLAC::MetadataBlock> > BlockList;
typedef BlockList::Iterator BlockIterator;
typedef BlockList::Iterator BlockConstIterator;
enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 };
const long MinPaddingLength = 4096;
const long MaxPaddingLegnth = 1024 * 1024;
const long long MinPaddingLength = 4096;
const long long MaxPaddingLegnth = 1024 * 1024;
const char LastBlockFlag = '\x80';
} // namespace
}
namespace TagLib
{
namespace FLAC
{
// Enables BlockList::find() to take raw pointers.
bool operator==(SHARED_PTR<MetadataBlock> lhs, MetadataBlock *rhs)
{
return lhs.get() == rhs;
}
}
}
class FLAC::File::FilePrivate
{
public:
FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) :
ID3v2FrameFactory(frameFactory)
explicit FilePrivate(const ID3v2::FrameFactory *frameFactory) :
ID3v2FrameFactory(ID3v2::FrameFactory::instance()),
ID3v2Location(-1),
ID3v2OriginalSize(0),
ID3v1Location(-1),
flacStart(0),
streamStart(0),
scanned(false)
{
blocks.setAutoDelete(true);
if(frameFactory)
ID3v2FrameFactory = frameFactory;
}
const ID3v2::FrameFactory *ID3v2FrameFactory;
offset_t ID3v2Location { -1 };
long ID3v2OriginalSize { 0 };
long long ID3v2Location;
long long ID3v2OriginalSize;
offset_t ID3v1Location { -1 };
long long ID3v1Location;
TagUnion tag;
TripleTagUnion tag;
std::unique_ptr<Properties> properties;
SCOPED_PTR<AudioProperties> properties;
ByteVector xiphCommentData;
List<FLAC::MetadataBlock *> blocks;
BlockList blocks;
offset_t flacStart { 0 };
offset_t streamStart { 0 };
bool scanned { false };
long long flacStart;
long long streamStart;
bool scanned;
};
////////////////////////////////////////////////////////////////////////////////
@@ -86,141 +113,47 @@ 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);
return (buffer.find("fLaC") != ByteVector::npos());
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
FLAC::File::File(FileName file, bool readProperties,
Properties::ReadStyle,
FLAC::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle,
ID3v2::FrameFactory *frameFactory) :
TagLib::File(file),
d(std::make_unique<FilePrivate>(
frameFactory ? frameFactory : ID3v2::FrameFactory::instance()))
d(new FilePrivate(frameFactory))
{
if(isOpen())
read(readProperties);
}
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle) :
TagLib::File(file),
d(std::make_unique<FilePrivate>(frameFactory))
{
if(isOpen())
read(readProperties);
}
FLAC::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle,
FLAC::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle,
ID3v2::FrameFactory *frameFactory) :
TagLib::File(stream),
d(std::make_unique<FilePrivate>(
frameFactory ? frameFactory : ID3v2::FrameFactory::instance()))
d(new FilePrivate(frameFactory))
{
if(isOpen())
read(readProperties);
}
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle) :
TagLib::File(stream),
d(std::make_unique<FilePrivate>(frameFactory))
FLAC::File::~File()
{
if(isOpen())
read(readProperties);
delete d;
}
FLAC::File::~File() = default;
TagLib::Tag *FLAC::File::tag() const
{
return &d->tag;
}
PropertyMap FLAC::File::properties() const
{
return d->tag.properties();
}
void FLAC::File::removeUnsupportedProperties(const StringList &unsupported)
{
d->tag.removeUnsupportedProperties(unsupported);
}
PropertyMap FLAC::File::setProperties(const PropertyMap &properties)
{
return xiphComment(true)->setProperties(properties);
}
StringList FLAC::File::complexPropertyKeys() const
{
StringList keys = TagLib::File::complexPropertyKeys();
if(!keys.contains("PICTURE")) {
if(std::any_of(d->blocks.cbegin(), d->blocks.cend(),
[](MetadataBlock *block) {
return dynamic_cast<Picture *>(block) != nullptr;
})) {
keys.append("PICTURE");
}
}
return keys;
}
List<VariantMap> FLAC::File::complexProperties(const String &key) const
{
const String uppercaseKey = key.upper();
if(uppercaseKey == "PICTURE") {
List<VariantMap> props;
for(const auto &block : std::as_const(d->blocks)) {
if(auto picture = dynamic_cast<Picture *>(block)) {
VariantMap property;
property.insert("data", picture->data());
property.insert("mimeType", picture->mimeType());
property.insert("description", picture->description());
property.insert("pictureType",
FLAC::Picture::typeToString(picture->type()));
property.insert("width", picture->width());
property.insert("height", picture->height());
property.insert("numColors", picture->numColors());
property.insert("colorDepth", picture->colorDepth());
props.append(property);
}
}
return props;
}
return TagLib::File::complexProperties(key);
}
bool FLAC::File::setComplexProperties(const String &key, const List<VariantMap> &value)
{
const String uppercaseKey = key.upper();
if(uppercaseKey == "PICTURE") {
removePictures();
for(const auto &property : value) {
auto picture = new FLAC::Picture;
picture->setData(property.value("data").value<ByteVector>());
picture->setMimeType(property.value("mimeType").value<String>());
picture->setDescription(property.value("description").value<String>());
picture->setType(FLAC::Picture::typeFromString(
property.value("pictureType").value<String>()));
picture->setWidth(property.value("width").value<int>());
picture->setHeight(property.value("height").value<int>());
picture->setNumColors(property.value("numColors").value<int>());
picture->setColorDepth(property.value("colorDepth").value<int>());
addPicture(picture);
}
}
else {
return TagLib::File::setComplexProperties(key, value);
}
return true;
}
FLAC::Properties *FLAC::File::audioProperties() const
FLAC::AudioProperties *FLAC::File::audioProperties() const
{
return d->properties.get();
}
@@ -245,40 +178,32 @@ bool FLAC::File::save()
// Replace metadata blocks
MetadataBlock *commentBlock =
new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData);
for(auto it = d->blocks.begin(); it != d->blocks.end();) {
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
if((*it)->code() == MetadataBlock::VorbisComment) {
// Remove the old Vorbis Comment block
delete *it;
it = d->blocks.erase(it);
continue;
// Set the new Vorbis Comment block
d->blocks.erase(it);
break;
}
if(commentBlock && (*it)->code() == MetadataBlock::Picture) {
// Set the new Vorbis Comment block before the first picture block
d->blocks.insert(it, commentBlock);
commentBlock = nullptr;
}
++it;
}
if(commentBlock)
d->blocks.append(commentBlock);
d->blocks.append(SHARED_PTR<MetadataBlock>(
new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)));
// Render data for the metadata blocks
ByteVector data;
for(const auto &block : std::as_const(d->blocks)) {
ByteVector blockData = block->render();
ByteVector blockHeader = ByteVector::fromUInt(blockData.size());
blockHeader[0] = block->code();
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
ByteVector blockData = (*it)->render();
ByteVector blockHeader = ByteVector::fromUInt32BE(blockData.size());
blockHeader[0] = (*it)->code();
data.append(blockHeader);
data.append(blockData);
}
// Compute the amount of padding, and append that to data.
offset_t originalLength = d->streamStart - d->flacStart;
offset_t paddingLength = originalLength - data.size() - 4;
long long originalLength = d->streamStart - d->flacStart;
long long paddingLength = originalLength - data.size() - 4;
if(paddingLength <= 0) {
paddingLength = MinPaddingLength;
@@ -286,22 +211,22 @@ bool FLAC::File::save()
else {
// Padding won't increase beyond 1% of the file size or 1MB.
offset_t threshold = length() / 100;
threshold = std::max<offset_t>(threshold, MinPaddingLength);
threshold = std::min<offset_t>(threshold, MaxPaddingLegnth);
long long threshold = length() / 100;
threshold = std::max(threshold, MinPaddingLength);
threshold = std::min(threshold, MaxPaddingLegnth);
if(paddingLength > threshold)
paddingLength = MinPaddingLength;
}
ByteVector paddingHeader = ByteVector::fromUInt(static_cast<unsigned int>(paddingLength));
ByteVector paddingHeader = ByteVector::fromUInt32BE(static_cast<unsigned int>(paddingLength));
paddingHeader[0] = static_cast<char>(MetadataBlock::Padding | LastBlockFlag);
data.append(paddingHeader);
data.resize(static_cast<unsigned int>(data.size() + paddingLength));
data.resize(static_cast<size_t>(data.size() + paddingLength));
// Write the data to the file
insert(data, d->flacStart, originalLength);
insert(data, d->flacStart, static_cast<size_t>(originalLength));
d->streamStart += (static_cast<long>(data.size()) - originalLength);
@@ -318,7 +243,7 @@ bool FLAC::File::save()
d->ID3v2Location = 0;
data = ID3v2Tag()->render();
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
insert(data, d->ID3v2Location, static_cast<size_t>(d->ID3v2OriginalSize));
d->flacStart += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
d->streamStart += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
@@ -333,7 +258,7 @@ bool FLAC::File::save()
// ID3v2 tag is empty. Remove the old one.
if(d->ID3v2Location >= 0) {
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
removeBlock(d->ID3v2Location, static_cast<size_t>(d->ID3v2OriginalSize));
d->flacStart -= d->ID3v2OriginalSize;
d->streamStart -= d->ID3v2OriginalSize;
@@ -375,8 +300,7 @@ bool FLAC::File::save()
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
{
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, create,
d->ID3v2FrameFactory);
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, create);
}
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
@@ -392,8 +316,9 @@ Ogg::XiphComment *FLAC::File::xiphComment(bool create)
List<FLAC::Picture *> FLAC::File::pictureList()
{
List<Picture *> pictures;
for(const auto &block : std::as_const(d->blocks)) {
if(auto picture = dynamic_cast<Picture *>(block)) {
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
Picture *picture = dynamic_cast<Picture *>(it->get());
if(picture) {
pictures.append(picture);
}
}
@@ -402,24 +327,20 @@ List<FLAC::Picture *> FLAC::File::pictureList()
void FLAC::File::addPicture(Picture *picture)
{
d->blocks.append(picture);
d->blocks.append(SHARED_PTR<Picture>(picture));
}
void FLAC::File::removePicture(Picture *picture, bool del)
void FLAC::File::removePicture(Picture *picture)
{
auto it = d->blocks.find(picture);
BlockIterator it = d->blocks.find(picture);
if(it != d->blocks.end())
d->blocks.erase(it);
if(del)
delete picture;
}
void FLAC::File::removePictures()
{
for(auto it = d->blocks.begin(); it != d->blocks.end(); ) {
if(dynamic_cast<Picture *>(*it)) {
delete *it;
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ) {
if(dynamic_cast<Picture *>(it->get())) {
it = d->blocks.erase(it);
}
else {
@@ -431,10 +352,10 @@ void FLAC::File::removePictures()
void FLAC::File::strip(int tags)
{
if(tags & ID3v1)
d->tag.set(FlacID3v1Index, nullptr);
d->tag.set(FlacID3v1Index, 0);
if(tags & ID3v2)
d->tag.set(FlacID3v2Index, nullptr);
d->tag.set(FlacID3v2Index, 0);
if(tags & XiphComment) {
xiphComment()->removeAllFields();
@@ -497,14 +418,14 @@ void FLAC::File::read(bool readProperties)
const ByteVector infoData = d->blocks.front()->render();
offset_t streamLength;
long long streamLength;
if(d->ID3v1Location >= 0)
streamLength = d->ID3v1Location - d->streamStart;
else
streamLength = length() - d->streamStart;
d->properties = std::make_unique<Properties>(infoData, streamLength);
d->properties.reset(new AudioProperties(infoData, streamLength));
}
}
@@ -518,7 +439,7 @@ void FLAC::File::scan()
if(!isValid())
return;
offset_t nextBlockOffset;
long long nextBlockOffset;
if(d->ID3v2Location >= 0)
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
@@ -538,11 +459,6 @@ 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
@@ -558,7 +474,7 @@ void FLAC::File::scan()
const char blockType = header[0] & ~LastBlockFlag;
const bool isLastBlock = (header[0] & LastBlockFlag) != 0;
const unsigned int blockLength = header.toUInt(1U, 3U);
const size_t blockLength = header.toUInt24BE(1);
// First block should be the stream_info metadata
@@ -583,33 +499,32 @@ void FLAC::File::scan()
return;
}
MetadataBlock *block = nullptr;
SHARED_PTR<MetadataBlock> block;
// Found the vorbis-comment
if(blockType == MetadataBlock::VorbisComment) {
if(d->xiphCommentData.isEmpty()) {
d->xiphCommentData = data;
block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, data);
block.reset(new UnknownMetadataBlock(MetadataBlock::VorbisComment, data));
}
else {
debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, discarding");
}
}
else if(blockType == MetadataBlock::Picture) {
auto picture = new FLAC::Picture();
SHARED_PTR<FLAC::Picture> picture(new FLAC::Picture());
if(picture->parse(data)) {
block = picture;
}
else {
debug("FLAC::File::scan() -- invalid picture found, discarding");
delete picture;
}
}
else if(blockType == MetadataBlock::Padding) {
// Skip all padding blocks.
}
else {
block = new UnknownMetadataBlock(blockType, data);
block.reset(new UnknownMetadataBlock(blockType, data));
}
if(block)

View File

@@ -26,10 +26,11 @@
#ifndef TAGLIB_FLACFILE_H
#define TAGLIB_FLACFILE_H
#include "taglib_export.h"
#include "tfile.h"
#include "tlist.h"
#include "taglib_export.h"
#include "tag.h"
#include "flacpicture.h"
#include "flacproperties.h"
@@ -82,73 +83,41 @@ namespace TagLib {
AllTags = 0xffff
};
/*!
* Constructs a FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*
* If this file contains an ID3v2 tag, the frames will be created using
* \a frameFactory (default if null).
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average,
ID3v2::FrameFactory *frameFactory = nullptr);
/*!
* Constructs an FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
* If this file contains an ID3v2 tag, the frames will be created using
* If this file contains and ID3v2 tag the frames will be created using
* \a frameFactory.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
TAGLIB_DEPRECATED
File(FileName file, ID3v2::FrameFactory *frameFactory,
File(FileName file,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average,
ID3v2::FrameFactory *frameFactory = 0);
/*!
* Constructs a FLAC file from \a stream. If \a readProperties is true the
* Constructs a FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* If this file contains an ID3v2 tag, the frames will be created using
* \a frameFactory (default if null).
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average,
ID3v2::FrameFactory *frameFactory = nullptr);
/*!
* Constructs a FLAC file from \a stream. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* If this file contains an ID3v2 tag, the frames will be created using
* If this file contains and ID3v2 tag the frames will be created using
* \a frameFactory.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*/
TAGLIB_DEPRECATED
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
File(IOStream *stream,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average,
ID3v2::FrameFactory *frameFactory = 0);
/*!
* Destroys this instance of the File.
*/
~File() override;
File(const File &) = delete;
File &operator=(const File &) = delete;
virtual ~File();
/*!
* Returns the Tag for this file. This will be a union of XiphComment,
@@ -158,17 +127,7 @@ namespace TagLib {
* \see ID3v1Tag()
* \see XiphComment()
*/
TagLib::Tag *tag() const override;
/*!
* Implements the unified property interface -- export function.
* If the file contains more than one tag (e.g. XiphComment and ID3v1),
* only the first one (in the order XiphComment, ID3v2, ID3v1) will be
* converted to the PropertyMap.
*/
PropertyMap properties() const override;
void removeUnsupportedProperties(const StringList &) override;
virtual TagLib::Tag *tag() const;
/*!
* Implements the unified property interface -- import function.
@@ -177,30 +136,13 @@ namespace TagLib {
* Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed
* in the FLAC specification.
*/
PropertyMap setProperties(const PropertyMap &) override;
/*!
* Returns ["PICTURE"] if any picture is stored in METADATA_BLOCK_PICTURE.
*/
StringList complexPropertyKeys() const override;
/*!
* Get the pictures stored in METADATA_BLOCK_PICTURE as complex properties
* for \a key "PICTURE".
*/
List<VariantMap> complexProperties(const String &key) const override;
/*!
* Set the complex properties \a value as pictures in METADATA_BLOCK_PICTURE
* for \a key "PICTURE".
*/
bool setComplexProperties(const String &key, const List<VariantMap> &value) override;
virtual PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the FLAC::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Properties *audioProperties() const override;
virtual AudioProperties *audioProperties() const;
/*!
* Save the file. This will primarily save the XiphComment, but
@@ -209,7 +151,7 @@ namespace TagLib {
*
* This returns true if the save was successful.
*/
bool save() override;
virtual bool save();
/*!
* Returns a pointer to the ID3v2 tag of the file.
@@ -274,10 +216,9 @@ namespace TagLib {
List<Picture *> pictureList();
/*!
* Removes an attached picture. If \a del is true the picture's memory
* will be freed; if it is false, it must be deleted by the user.
* Removes an attached picture. The picture's memory will be freed.
*/
void removePicture(Picture *picture, bool del = true);
void removePicture(Picture *picture);
/*!
* Remove all attached images.
@@ -338,14 +279,16 @@ namespace TagLib {
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties);
void scan();
class FilePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FilePrivate> d;
FilePrivate *d;
};
} // namespace FLAC
} // namespace TagLib
}
}
#endif

View File

@@ -23,14 +23,25 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <taglib.h>
#include <tdebug.h>
#include "flacmetadatablock.h"
using namespace TagLib;
class FLAC::MetadataBlock::MetadataBlockPrivate
{
public:
MetadataBlockPrivate() {}
};
FLAC::MetadataBlock::MetadataBlock() = default;
FLAC::MetadataBlock::MetadataBlock()
{
d = 0;
}
FLAC::MetadataBlock::~MetadataBlock()
{
}
FLAC::MetadataBlock::~MetadataBlock() = default;

View File

@@ -31,16 +31,15 @@
#include "taglib_export.h"
namespace TagLib {
namespace FLAC {
class TAGLIB_EXPORT MetadataBlock
{
public:
MetadataBlock();
virtual ~MetadataBlock();
MetadataBlock(const MetadataBlock &item) = delete;
MetadataBlock &operator=(const MetadataBlock &item) = delete;
enum BlockType {
StreamInfo = 0,
Padding,
@@ -62,10 +61,15 @@ namespace TagLib {
virtual ByteVector render() const = 0;
private:
MetadataBlock(const MetadataBlock &item);
MetadataBlock &operator=(const MetadataBlock &item);
class MetadataBlockPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<MetadataBlockPrivate> d;
MetadataBlockPrivate *d;
};
} // namespace FLAC
} // namespace TagLib
}
}
#endif

View File

@@ -23,37 +23,48 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <taglib.h>
#include <tdebug.h>
#include "flacpicture.h"
#include "tdebug.h"
using namespace TagLib;
class FLAC::Picture::PicturePrivate
{
public:
Type type { FLAC::Picture::Other };
PicturePrivate() :
type(FLAC::Picture::Other),
width(0),
height(0),
colorDepth(0),
numColors(0)
{}
Type type;
String mimeType;
String description;
int width { 0 };
int height { 0 };
int colorDepth { 0 };
int numColors { 0 };
int width;
int height;
int colorDepth;
int numColors;
ByteVector data;
};
FLAC::Picture::Picture() :
d(std::make_unique<PicturePrivate>())
d(new PicturePrivate())
{
}
FLAC::Picture::Picture(const ByteVector &data) :
d(std::make_unique<PicturePrivate>())
d(new PicturePrivate())
{
parse(data);
}
FLAC::Picture::~Picture() = default;
FLAC::Picture::~Picture()
{
delete d;
}
int FLAC::Picture::code() const
{
@@ -67,10 +78,10 @@ bool FLAC::Picture::parse(const ByteVector &data)
return false;
}
unsigned int pos = 0;
d->type = static_cast<FLAC::Picture::Type>(data.toUInt(pos));
size_t pos = 0;
d->type = FLAC::Picture::Type(data.toUInt32BE(pos));
pos += 4;
unsigned int mimeTypeLength = data.toUInt(pos);
const unsigned int mimeTypeLength = data.toUInt32BE(pos);
pos += 4;
if(pos + mimeTypeLength + 24 > data.size()) {
debug("Invalid picture block.");
@@ -78,7 +89,7 @@ bool FLAC::Picture::parse(const ByteVector &data)
}
d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8);
pos += mimeTypeLength;
unsigned int descriptionLength = data.toUInt(pos);
const unsigned int descriptionLength = data.toUInt32BE(pos);
pos += 4;
if(pos + descriptionLength + 20 > data.size()) {
debug("Invalid picture block.");
@@ -86,15 +97,15 @@ bool FLAC::Picture::parse(const ByteVector &data)
}
d->description = String(data.mid(pos, descriptionLength), String::UTF8);
pos += descriptionLength;
d->width = data.toUInt(pos);
d->width = data.toUInt32BE(pos);
pos += 4;
d->height = data.toUInt(pos);
d->height = data.toUInt32BE(pos);
pos += 4;
d->colorDepth = data.toUInt(pos);
d->colorDepth = data.toUInt32BE(pos);
pos += 4;
d->numColors = data.toUInt(pos);
d->numColors = data.toUInt32BE(pos);
pos += 4;
unsigned int dataLength = data.toUInt(pos);
const unsigned int dataLength = data.toUInt32BE(pos);
pos += 4;
if(pos + dataLength > data.size()) {
debug("Invalid picture block.");
@@ -108,18 +119,18 @@ bool FLAC::Picture::parse(const ByteVector &data)
ByteVector FLAC::Picture::render() const
{
ByteVector result;
result.append(ByteVector::fromUInt(d->type));
result.append(ByteVector::fromUInt32BE(d->type));
ByteVector mimeTypeData = d->mimeType.data(String::UTF8);
result.append(ByteVector::fromUInt(mimeTypeData.size()));
result.append(ByteVector::fromUInt32BE(mimeTypeData.size()));
result.append(mimeTypeData);
ByteVector descriptionData = d->description.data(String::UTF8);
result.append(ByteVector::fromUInt(descriptionData.size()));
result.append(ByteVector::fromUInt32BE(descriptionData.size()));
result.append(descriptionData);
result.append(ByteVector::fromUInt(d->width));
result.append(ByteVector::fromUInt(d->height));
result.append(ByteVector::fromUInt(d->colorDepth));
result.append(ByteVector::fromUInt(d->numColors));
result.append(ByteVector::fromUInt(d->data.size()));
result.append(ByteVector::fromUInt32BE(d->width));
result.append(ByteVector::fromUInt32BE(d->height));
result.append(ByteVector::fromUInt32BE(d->colorDepth));
result.append(ByteVector::fromUInt32BE(d->numColors));
result.append(ByteVector::fromUInt32BE(d->data.size()));
result.append(d->data);
return result;
}
@@ -203,3 +214,4 @@ void FLAC::Picture::setData(const ByteVector &data)
{
d->data = data;
}

View File

@@ -29,12 +29,13 @@
#include "tlist.h"
#include "tstring.h"
#include "tbytevector.h"
#include "tpicturetype.h"
#include "taglib_export.h"
#include "flacmetadatablock.h"
namespace TagLib {
namespace FLAC {
class TAGLIB_EXPORT Picture : public MetadataBlock
{
public:
@@ -42,14 +43,54 @@ namespace TagLib {
/*!
* This describes the function or content of the picture.
*/
DECLARE_PICTURE_TYPE_ENUM(Type)
enum Type {
//! A type not enumerated below
Other = 0x00,
//! 32x32 PNG image that should be used as the file icon
FileIcon = 0x01,
//! File icon of a different size or format
OtherFileIcon = 0x02,
//! Front cover image of the album
FrontCover = 0x03,
//! Back cover image of the album
BackCover = 0x04,
//! Inside leaflet page of the album
LeafletPage = 0x05,
//! Image from the album itself
Media = 0x06,
//! Picture of the lead artist or soloist
LeadArtist = 0x07,
//! Picture of the artist or performer
Artist = 0x08,
//! Picture of the conductor
Conductor = 0x09,
//! Picture of the band or orchestra
Band = 0x0A,
//! Picture of the composer
Composer = 0x0B,
//! Picture of the lyricist or text writer
Lyricist = 0x0C,
//! Picture of the recording location or studio
RecordingLocation = 0x0D,
//! Picture of the artists during recording
DuringRecording = 0x0E,
//! Picture of the artists during performance
DuringPerformance = 0x0F,
//! Picture from a movie or video related to the track
MovieScreenCapture = 0x10,
//! Picture of a large, coloured fish
ColouredFish = 0x11,
//! Illustration related to the track
Illustration = 0x12,
//! Logo of the band or performer
BandLogo = 0x13,
//! Logo of the publisher (record company)
PublisherLogo = 0x14
};
Picture();
Picture(const ByteVector &data);
~Picture() override;
Picture(const Picture &item) = delete;
Picture &operator=(const Picture &item) = delete;
explicit Picture(const ByteVector &data);
~Picture();
/*!
* Returns the type of the image.
@@ -138,12 +179,12 @@ namespace TagLib {
/*!
* Returns the FLAC metadata block type.
*/
int code() const override;
int code() const;
/*!
* Render the content to the FLAC picture block format.
*/
ByteVector render() const override;
ByteVector render() const;
/*!
* Parse the picture data in the FLAC picture block format.
@@ -151,12 +192,15 @@ namespace TagLib {
bool parse(const ByteVector &rawData);
private:
Picture(const Picture &item);
Picture &operator=(const Picture &item);
class PicturePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<PicturePrivate> d;
PicturePrivate *d;
};
using PictureList = List<Picture>;
} // namespace FLAC
} // namespace TagLib
}
}
#endif

View File

@@ -23,24 +23,31 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "flacproperties.h"
#include "tstring.h"
#include "tdebug.h"
#include "flacfile.h"
using namespace TagLib;
class FLAC::Properties::PropertiesPrivate
class FLAC::AudioProperties::PropertiesPrivate
{
public:
int length { 0 };
int bitrate { 0 };
int sampleRate { 0 };
int bitsPerSample { 0 };
int channels { 0 };
unsigned long long sampleFrames { 0 };
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
bitsPerSample(0),
channels(0),
sampleFrames(0) {}
int length;
int bitrate;
int sampleRate;
int bitsPerSample;
int channels;
unsigned long long sampleFrames;
ByteVector signature;
};
@@ -48,46 +55,64 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
FLAC::Properties::Properties(const ByteVector &data, offset_t streamLength, ReadStyle style) :
AudioProperties(style),
d(std::make_unique<PropertiesPrivate>())
FLAC::AudioProperties::AudioProperties(const ByteVector &data, long long streamLength, ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
read(data, streamLength);
}
FLAC::Properties::~Properties() = default;
FLAC::AudioProperties::~AudioProperties()
{
delete d;
}
int FLAC::Properties::lengthInMilliseconds() const
int FLAC::AudioProperties::length() const
{
return lengthInSeconds();
}
int FLAC::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int FLAC::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int FLAC::Properties::bitrate() const
int FLAC::AudioProperties::bitrate() const
{
return d->bitrate;
}
int FLAC::Properties::sampleRate() const
int FLAC::AudioProperties::sampleRate() const
{
return d->sampleRate;
}
int FLAC::Properties::bitsPerSample() const
int FLAC::AudioProperties::bitsPerSample() const
{
return d->bitsPerSample;
}
int FLAC::Properties::channels() const
int FLAC::AudioProperties::sampleWidth() const
{
return bitsPerSample();
}
int FLAC::AudioProperties::channels() const
{
return d->channels;
}
unsigned long long FLAC::Properties::sampleFrames() const
unsigned long long FLAC::AudioProperties::sampleFrames() const
{
return d->sampleFrames;
}
ByteVector FLAC::Properties::signature() const
ByteVector FLAC::AudioProperties::signature() const
{
return d->signature;
}
@@ -96,14 +121,14 @@ ByteVector FLAC::Properties::signature() const
// private members
////////////////////////////////////////////////////////////////////////////////
void FLAC::Properties::read(const ByteVector &data, offset_t streamLength)
void FLAC::AudioProperties::read(const ByteVector &data, long long streamLength)
{
if(data.size() < 18) {
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
debug("FLAC::AudioProperties::read() - FLAC properties must contain at least 18 bytes.");
return;
}
unsigned int pos = 0;
size_t pos = 0;
// Minimum block size (in samples)
pos += 2;
@@ -117,7 +142,7 @@ void FLAC::Properties::read(const ByteVector &data, offset_t streamLength)
// Maximum frame size (in bytes)
pos += 3;
const unsigned int flags = data.toUInt(pos, true);
const unsigned int flags = data.toUInt32BE(pos);
pos += 4;
d->sampleRate = flags >> 12;
@@ -128,7 +153,7 @@ void FLAC::Properties::read(const ByteVector &data, offset_t streamLength)
// stream length in samples. (Audio files measured in days)
const unsigned long long hi = flags & 0xf;
const unsigned long long lo = data.toUInt(pos, true);
const unsigned long long lo = data.toUInt32BE(pos);
pos += 4;
d->sampleFrames = (hi << 32) | lo;

View File

@@ -26,7 +26,6 @@
#ifndef TAGLIB_FLACPROPERTIES_H
#define TAGLIB_FLACPROPERTIES_H
#include "tbytevector.h"
#include "taglib_export.h"
#include "audioproperties.h"
@@ -34,6 +33,8 @@ namespace TagLib {
namespace FLAC {
class File;
//! An implementation of audio property reading for FLAC
/*!
@@ -41,44 +42,59 @@ namespace TagLib {
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
public:
/*!
* Create an instance of FLAC::Properties with the data read from the
* ByteVector \a data.
* Creates an instance of FLAC::AudioProperties with the data read from
* the ByteVector \a data.
*/
Properties(const ByteVector &data, offset_t streamLength, ReadStyle style = Average);
AudioProperties(const ByteVector &data, long long streamLength, ReadStyle style = Average);
/*!
* Destroys this FLAC::Properties instance.
* Destroys this FLAC::AudioProperties instance.
*/
~Properties() override;
virtual ~AudioProperties();
Properties(const Properties &) = delete;
Properties &operator=(const Properties &) = delete;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
virtual int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
int lengthInMilliseconds() const override;
virtual int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
int bitrate() const override;
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
int sampleRate() const override;
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
int channels() const override;
virtual int channels() const;
/*!
* Returns the number of bits per audio sample as read from the FLAC
@@ -86,6 +102,16 @@ namespace TagLib {
*/
int bitsPerSample() const;
/*!
* Returns the sample width as read from the FLAC identification
* header.
*
* \note This method is just an alias of bitsPerSample().
*
* \deprecated
*/
int sampleWidth() const;
/*!
* Return the number of sample frames.
*/
@@ -98,13 +124,12 @@ namespace TagLib {
ByteVector signature() const;
private:
void read(const ByteVector &data, offset_t streamLength);
void read(const ByteVector &data, long long streamLength);
class PropertiesPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<PropertiesPrivate> d;
PropertiesPrivate *d;
};
} // namespace FLAC
} // namespace TagLib
}
}
#endif

View File

@@ -23,6 +23,9 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <taglib.h>
#include <tdebug.h>
#include <tstring.h>
#include "flacunknownmetadatablock.h"
using namespace TagLib;
@@ -30,18 +33,23 @@ using namespace TagLib;
class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate
{
public:
int code { 0 };
UnknownMetadataBlockPrivate() : code(0) {}
int code;
ByteVector data;
};
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) :
d(std::make_unique<UnknownMetadataBlockPrivate>())
d(new UnknownMetadataBlockPrivate())
{
d->code = code;
d->data = data;
}
FLAC::UnknownMetadataBlock::~UnknownMetadataBlock() = default;
FLAC::UnknownMetadataBlock::~UnknownMetadataBlock()
{
delete d;
}
int FLAC::UnknownMetadataBlock::code() const
{
@@ -67,3 +75,4 @@ ByteVector FLAC::UnknownMetadataBlock::render() const
{
return d->data;
}

View File

@@ -32,20 +32,19 @@
#include "flacmetadatablock.h"
namespace TagLib {
namespace FLAC {
class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock
{
public:
UnknownMetadataBlock(int code, const ByteVector &data);
~UnknownMetadataBlock() override;
UnknownMetadataBlock(const UnknownMetadataBlock &item) = delete;
UnknownMetadataBlock &operator=(const UnknownMetadataBlock &item) = delete;
UnknownMetadataBlock(int blockType, const ByteVector &data);
~UnknownMetadataBlock();
/*!
* Returns the FLAC metadata block type.
*/
int code() const override;
int code() const;
/*!
* Sets the FLAC metadata block type.
@@ -65,13 +64,18 @@ namespace TagLib {
/*!
* Render the content of the block.
*/
ByteVector render() const override;
ByteVector render() const;
private:
UnknownMetadataBlock(const MetadataBlock &item);
UnknownMetadataBlock &operator=(const MetadataBlock &item);
class UnknownMetadataBlockPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<UnknownMetadataBlockPrivate> d;
UnknownMetadataBlockPrivate *d;
};
} // namespace FLAC
} // namespace TagLib
}
}
#endif

View File

@@ -23,12 +23,12 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "itfile.h"
#include "tstringlist.h"
#include "itfile.h"
#include "tdebug.h"
#include "tpropertymap.h"
#include "modfileprivate.h"
#include "tpropertymap.h"
using namespace TagLib;
using namespace IT;
@@ -36,19 +36,19 @@ using namespace IT;
class IT::File::FilePrivate
{
public:
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
: properties(propertiesStyle)
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle)
: tag(), properties(propertiesStyle)
{
}
Mod::Tag tag;
IT::Properties properties;
IT::AudioProperties properties;
};
IT::File::File(FileName file, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) :
Mod::FileBase(file),
d(std::make_unique<FilePrivate>(propertiesStyle))
d(new FilePrivate(propertiesStyle))
{
if(isOpen())
read(readProperties);
@@ -57,20 +57,23 @@ IT::File::File(FileName file, bool readProperties,
IT::File::File(IOStream *stream, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) :
Mod::FileBase(stream),
d(std::make_unique<FilePrivate>(propertiesStyle))
d(new FilePrivate(propertiesStyle))
{
if(isOpen())
read(readProperties);
}
IT::File::~File() = default;
IT::File::~File()
{
delete d;
}
Mod::Tag *IT::File::tag() const
{
return &d->tag;
}
IT::Properties *IT::File::audioProperties() const
IT::AudioProperties *IT::File::audioProperties() const
{
return &d->properties;
}
@@ -100,8 +103,8 @@ 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 + (static_cast<long>(i) << 2));
unsigned long instrumentOffset = 0;
seek(192L + length + ((long)i << 2));
unsigned int instrumentOffset = 0;
if(!readU32L(instrumentOffset))
return false;
@@ -115,14 +118,14 @@ bool IT::File::save()
}
for(unsigned short i = 0; i < sampleCount; ++ i) {
seek(192L + length + (static_cast<long>(instrumentCount) << 2) + (static_cast<long>(i) << 2));
unsigned long sampleOffset = 0;
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
unsigned int sampleOffset = 0;
if(!readU32L(sampleOffset))
return false;
seek(sampleOffset + 20);
if(static_cast<unsigned int>(i + instrumentCount) < lines.size())
if((unsigned int)(i + instrumentCount) < lines.size())
writeString(lines[i + instrumentCount], 25);
else
writeString(String(), 25);
@@ -139,18 +142,18 @@ bool IT::File::save()
// terminating NUL but it does not hurt to add one:
if(message.size() > 7999)
message.resize(7999);
message.append(static_cast<char>(0));
message.append((char)0);
unsigned short special = 0;
unsigned short messageLength = 0;
unsigned long messageOffset = 0;
unsigned int messageOffset = 0;
seek(46);
if(!readU16L(special))
return false;
auto fileSize = static_cast<unsigned long>(File::length());
if(special & Properties::MessageAttached) {
unsigned int fileSize = static_cast<unsigned int>(File::length());
if(special & AudioProperties::MessageAttached) {
seek(54);
if(!readU16L(messageLength) || !readU32L(messageOffset))
return false;
@@ -168,7 +171,7 @@ bool IT::File::save()
if(messageOffset + messageLength >= fileSize) {
// append new message
seek(54);
writeU16L(message.size());
writeU16L(static_cast<unsigned short>(message.size()));
writeU32L(messageOffset);
seek(messageOffset);
writeBlock(message);
@@ -220,14 +223,14 @@ void IT::File::read(bool)
// sample/instrument names are abused as comments so
// I just add all together.
String message;
if(special & Properties::MessageAttached) {
if(special & AudioProperties::MessageAttached) {
READ_U16L_AS(messageLength);
READ_U32L_AS(messageOffset);
seek(messageOffset);
ByteVector messageBytes = readBlock(messageLength);
READ_ASSERT(messageBytes.size() == messageLength);
int index = messageBytes.find(static_cast<char>(0));
if(index > -1)
const size_t index = messageBytes.find((char) 0);
if(index != ByteVector::npos())
messageBytes.resize(index, 0);
messageBytes.replace('\r', '\n');
message = messageBytes;
@@ -244,8 +247,8 @@ void IT::File::read(bool)
// I don't count disabled and muted channels.
// But this always gives 64 channels for all my files anyway.
// Strangely VLC does report other values. I wonder how VLC
// gets its values.
if(static_cast<unsigned char>(pannings[i]) < 128 && volumes[i] > 0)
// gets it's values.
if((unsigned char) pannings[i] < 128 && volumes[i] > 0)
++channels;
}
d->properties.setChannels(channels);
@@ -264,10 +267,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 interpret a nil as a space. I
// e.g. VLC seems to interprete 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 + (static_cast<long>(i) << 2));
seek(192L + length + ((long)i << 2));
READ_U32L_AS(instrumentOffset);
seek(instrumentOffset);
@@ -283,7 +286,7 @@ void IT::File::read(bool)
}
for(unsigned short i = 0; i < sampleCount; ++ i) {
seek(192L + length + (static_cast<long>(instrumentCount) << 2) + (static_cast<long>(i) << 2));
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
READ_U32L_AS(sampleOffset);
seek(sampleOffset);
@@ -315,7 +318,7 @@ void IT::File::read(bool)
comment.append(sampleName);
}
if(!message.isEmpty())
if(message.size() > 0)
comment.append(message);
d->tag.setComment(comment.toString("\n"));
d->tag.setTrackerName("Impulse Tracker");

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